最近在给组人员准备分享java内存相关东东,于是又把java内存相关知识复习了一遍,今天特此写出来分享下,如有不对的地方,望大家指出。
java内存的重要性:C++从一个对象创建,到这个对象的内存的free/delete,都需要靠程序员自己编码实现。但是Java从一个对象创建,到这个对象内存的释放,都是由JVM自己控制,从而内存泄露,java程序员排查起来,就需要懂得JVM相关内存的知识。
java中有内存有堆、栈(虚拟机栈和本地方法栈)、方法区(运行时常量池)、直接内存、程序计数器等几部分构成。
要掌握每种内存,就要了解每种内存,需掌握每种内存以下几个方面:1)这个内存用途,存些什么东西,是否线程安全(线程私有还是共有) 2)如果溢出,会抛出什么异常 3)怎么样设置其大小。接下来,从以下几个方面,意义介绍这些东东。
1、程序计数器:1)当前线程执行字节码的行号指示器,很小的内存空间。如果执行为native方法,则为空。线程私有。2)无OutOfMemory 。
2、栈:1)分为虚拟机栈和本地方法栈,虚拟机栈为java方法执行的内存模型:每个方法执行时候都会同时创建一个栈帧用户存储局部变量表、操作数栈、动态链接和方法出口等信息。每一个方法的执行完成过程,就是虚拟机栈入栈和出栈的过程。本地方法栈与虚拟机栈类似,只不过执行的是native方法而已。虚拟机栈是线程私有的 2)异常时会抛出OutOfMemoryError和StackOverflowError 3)-xss来设置每个线程中栈帧的大小
3、堆:java内存中最大的一块,主要用来存放对象的实例。java虚拟机规范:java中所有的对象实例和数组都要在堆中分配。但是随着JVM发展(JIT编译以及逃逸分析),栈上分配、标量替换等,所有对象都在堆中分配也不那么绝对了。Java堆是垃圾回收的主要区域,具体可分为新生代、老生代。TLAB(Thread Local Allocation Buffer):java堆中划分出多个线程私有的分配缓冲区。java堆是线程共有的 2)通过-Xmx和-Xms控制其大小 3)溢出时会抛出OutOfMemoryError异常
4、方法区,这一区域主要用来储存虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。Hotpot虚拟机中的永久代与方法区并不等价,只不过是在永久代实现了方法区而已。这里的垃圾回收很少,java虚拟机规范说这里也可以不实现垃圾回收。这里的内存回收只是针对与类型卸载与常量池回收。运行时常量池也是来及回收的一部分,主要存放编译器生各种字面量和符号引用(常量池),也会把翻译出来的直接引用存入运行时常量池。这个区域是线程共有的。2)通过-XX:PermSize和-XXMaxPermSize来设置这个区域大小 3)溢出时会抛出OutOfMemoryError异常
5、直接内存:直接内存不是java虚拟机运行时数据一部分,也不是java虚拟规范定义的内存区域。这部分内存主要用来储存NIO中缓冲区(Buffer)的数据,也可以使用Native函数库直接分配堆外内存。2)可以通过--MaxDirectMemorySize来指定它的大小。如果不指定,默认和堆内存一样大。3)溢出时会抛出OutOfMemoryError异常
本文参考于《深入理解Java虚拟机》。