🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## Java运行时数据区 **如下内容如未说明均以JDK1.7版本为准** ![](https://img.kancloud.cn/0c/82/0c8211833cd19dccf20f783a94c4953d_1074x994.png) JVM内存主要分为5个部分: * 程序计数器 * 虚拟机栈 * 本地方法栈 * 堆 * 方法区 ![](https://img.kancloud.cn/68/3b/683bdd85029b005e269cec3658ca2607_1440x1000.png) 而JDK1.8和JDK1.7比,主要是将**方法区(永久代)** 被 **元数据区**取代,而且不再在在虚拟机内存中,而是使用的本地内存。 ## 程序计数器 ![](https://img.kancloud.cn/3b/97/3b9772f588c308c2a101d8e7422da82c_1462x1022.png) 1. 程序计数器是一块较小内存空间,可以看做是当前线程的行号指示器,是线程私有的。 2. 字节码解释器工作时就是通过改变计数器的值来选取下一条需要执行的字节码指令,来完成分支、循环、跳转、异常处理、线程恢复等基础功能。 3. 当前线程正在执行Java方法时,计数器记录的是虚拟机字节码指令地址;正在执行的是Native方法时,计数器值为空(Undefined)。 ## 虚拟机栈 ## 本地方法栈 ## 堆 ![](https://img.kancloud.cn/93/8b/938bb88e07b0ef64f90750466a7f34b3_1454x662.png) 1. Java堆是虚拟机中最大的一块区域,是线程共享的,按垃圾的分代收集算法细分为老年代和新生代,新生代又分为Eden区和幸存区,幸存区又分为From和to区。 2. 线程本地缓存区(TLAB)位于Eden区,是虚拟机保证对象的内存分配的线程安全的技术。每个线程都会有一个很小的TLAB空间,对象分配内存空间时,优先在自己的TLAB中分配,再在老年代中分配。所以堆里的TLAB区域是线程独享的。 3. 所有对象实例及数组都要在堆上分配,除一些优化情况外(JIT编译器优化和逃逸技术,出现栈上分配、标量替换优化)。 ## 方法区 ![](https://img.kancloud.cn/e2/5e/e25eeaed0afe982f70d74e1e72799931_1456x816.png) 1. 虚拟机规范中定义方法区是堆的一个逻辑部分,不需要连续内存或者可扩展外,还可以不实现垃圾回收。 2. 方法区用于存放已加载的类信息、常量、静态变量和即时编译器编译后的代码。 3. 方法区内的回收主要针对常量池的回收和类的卸载。 4. 运行时常量池是方法区的一部分,存放类加载后class文件的常量信息以及String.inter()产生的新的常量。 ## 直接内存 1. 直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。 2. JDK1.4之后新加入了NIO,可以通过DirectByteBuffer类来创建和使用堆外内存,因为避免了在Java堆和Native堆中来回复制数据,从而显著提高性能。 3. 虽然是堆外内存,但是也会受到物理内存大小的限制,所以在动态扩展时可能会出现OOM异常。 ## 参考资料 * 周志明 * 《深入理解Java虚拟机》