Chinaunix首页 | 论坛 | 博客
  • 博客访问: 278228
  • 博文数量: 58
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 600
  • 用 户 组: 普通用户
  • 注册时间: 2015-11-27 08:37
个人简介

从linux了解世界

文章分类
文章存档

2017年(5)

2016年(51)

2015年(2)

我的朋友

分类: Java

2016-07-30 12:58:04

昨天蚂蚁金服的面试被问到了这个问题,凭借之前了解到的内容回答的不好,对这块内容的了解太零散不成系统,今天看到了一篇博文写的很系统具体,结合自己之前的认识总结下,原文博客地址http://blog.chinaunix.net/uid-20586655-id-2235728.html
jvm内部结构:两个子系统分别是Class loader子系统Execution engine(执行引擎) 子系统。两个组件分别是Runtime data area (运行时数据区域)组件和Native interface(本地接口)组件。其中Runtime data area就是我们平时说的jvm内存模型。

一、类加载子系统:根据给定的全限定名类名(如 java.lang.Object)来装载class文件的内容到 Runtime data area中。Java程序员可以extends java.lang.ClassLoader类来写自己的Class loader。
二、执行引擎:java虚拟机的核心都是Execution engine,不同虚拟机的好坏主要就取决于他们各自实现的Execution engine的好坏。
三、Native interface组件:与native libraries交互,是其它编程语言交互的接口。当调用native方法的时候,就进入了一个全新的并且不再受虚拟机限制的世界,所以也很容易出现JVM无法控制的native heap OutOfMemory。
四、Runtime Data Area组件:这就是我们常说的JVM的内存了。它主要分为五个部分:
        1、Heap (堆):一个Java虚拟实例中只存在一个堆空间,Java堆是被所有线程共享的,在虚拟机启动时创建。Java堆的唯一目的就是存放对象实例,绝大部分的对象实例都在这里分配。Java堆内还有更细致的划分:新生代、老年代,再细致一点的:eden、from survivor、to survivor,无论对Java堆如何划分,目的都是为了更好的回收内存,或者更快的分配内存Java堆可以处于物理上不连续的内存空间,它逻辑上是连续的即可,就像我们的磁盘空间一样。实现时可以选择实现成固定大小的,也可以是可扩展的,不过当前所有商业的虚拟机都是按照可扩展来实现的(通过-Xmx和-Xms控制)。如果在堆中无法分配内存,并且堆也无法再扩展时,将会抛出OutOfMemoryError异常。
        2、Method Area(方法区域):被装载的class的信息存储在Method area的内存中,其实也可与看成堆内存的一部分,GC也会回收,但很少回收。当虚拟机装载某个类型时,它使用类装载器定位相应的class文件,然后读入这个class文件内容并把它传输到虚拟机中。叫“方法区”可能认识它的人还不太多,如果叫永久代(Permanent Generation)它的粉丝也许就多了。它还有个别名叫做Non-Heap(非堆)。方法区中存放了每个Class的结构信息,包括常量池、字段描述、方法描述等等。Class文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量表(constant_pool table),用于存放编译期已可知的常量,这部分内容将在类加载后进入方法区(永久代)存放。但是Java语言并不要求常量一定只有编译期预置入Class的常量表的内容才能进入方法区常量池,运行期间也可将新内容放入常量池(最典型的String.intern()方法)。运行时常量池是方法区的一部分,自然受到方法区内存的限制,当常量池无法在申请到内存时会抛出OutOfMemoryError异常。
        3、Java Stack(java的栈):虚拟机只会直接对Java stack执行两种操作:以帧为单位的压栈或出栈。栈描述的是Java方法调用的内存模型:每个方法被执行的时候,都会同时创建一个帧(Frame)用于存储本地变量表、操作栈、动态链接、方法出入口等信息。每一个方法的调用至完成,就意味着一个帧在VM栈中的入栈至出栈的过程。
        4、Program Counter(程序计数器):每一个线程都有它自己的PC寄存器,也是该线程启动时创建的。PC寄存器的内容总是指向下一条将被执行指令的饿地址,这里的地址可以是一个本地指针,也可以是在方法区中相对应于该方法起始指令的偏移量。 
        5、Native method stack(本地方法栈):保存native方法进入区域的地址.
以上五部分只有Heap 和Method Area是被所有线程的共享使用的;而Java stack, Program counter 和Native method stack是以线程为粒度的,每个线程独自拥有自己的部分。
堆内存优化:
-server时最大堆内存是物理内存的1/4,但小于1G,client为一半。
调整JVM启动参数-Xms、-Xmx、-XX:newSize、-XX:MaxNewSize,如调整初始堆内存和最大对内存 -Xms256M -Xmx512M。 或者调整初始New Generation的初始内存和最大内存 -XX:newSize=128M -XX:MaxNewSize=128M。

永久区内存优化:
调整PermSize参数   如  -XX:PermSize=256M -XX:MaxPermSize=512M。

栈内存优化:
调整每个线程的栈内存容量  如  -Xss2048K
阅读(1487) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~