1.1 内存结构
1、两个子系统:Class loader子系统和Execution engine(执行引擎)子系统
(1)Class loader子系统
根据给定的全限定名类名(如java.lang.Object)来装载class文件的内容到Runtime data area中的method area(方法区域)
(2)Execution engine子系统
执行classes中的指令。任何JVM specification实现(JDK)的核心都是Execution engine
2、两个组件:Runtime data area(运行时数据区域)组件和Native interface(本地接口)组件
(1)Native interface组件
与native libraries交互,是与其它编程语言交互的接口。当调用native方法的时候,就进入了一个全新的并且不再受虚拟机限制的世界。
(2)Runtime Data Area组件——JVM的内存
Heap(堆):一个Java虚拟实例中只存在一个堆空间,用于存储对象实例及数组值,可以认为Java中所有通过new创建的对象的内存都在此分配,其大小可以通过-Xmx和-Xms来控制。
堆被划分为新生代和旧生代,新生代又被进一步划分为Eden和Survivor区,Survivor由S0和S1组成。新建的对象都是用新生代分配内存;旧生代用于存放新生代中经过多次垃圾回收仍然存活的对象
Method Area(方法区域):被装载的class的信息存储在Method area的内存中。当虚拟机装载某个类型时,它使用类装载器定位相应的class文件,然后读入这个class文件内容并把它传输到虚拟机中。在Sun JDK中这块区域对应 Permanent Space,又称永久代。
可能抛出异常: java.lang.OutOfMemoryError: PermGen space
Java Stack(java的栈):虚拟机只会直接对Java stack执行两种操作:以帧为单位的压栈或出栈,Java栈为线程私有,当方法运行完毕,对应的栈帧所占用内存自动释放。可以通过-Xss来指定大小。
可能抛出异常: StackOverflowError
Program Counter(程序计数器):每一个线程都有它自己的PC寄存器,也是该线程启动时创建的。PC寄存器的内容总是指向下一条将被执行指令的地址。
Native method stack(本地方法栈):保存native方法进入区域的地址,用于支持native方法的执行,存储了每个native方法调用的状态。当一个线程调用本地方法时,它就不再受到虚拟机关于结构和安全限制方面的约束,它既可以访问虚拟机的运行期数据区,也可以使用本地处理 器以及任何类型的栈。
1.2 内存分配
1、堆(Heap)和非堆(Non-heap)内存
堆:就是Java代码可及的内存,是留给开发人员使用的。
非堆:就是JVM留给自己用的,所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法的代码都在非堆内存中。
2、堆内存分配
JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC后调整堆的大小。
3、非堆内存分配
JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。
4、JVM内存限制(最大值)
首先JVM内存限制于实际的最大物理内存,假设物理内存无限大的话,JVM内存的最大值跟操作系统有很大的关系。简单的说就32位处理器虽然可控内存空间有4GB,但是具体的操作系统会给一个限制,这个限制一般是2GB-3GB(一般来说Windows系统下为1.5G-2G,Linux系统下为2G-3G),而64bit以上的处理器就不会有限制了。
欢迎关注公众号: