jvm 内存模型

104 阅读3分钟

根据JVM规范,JVM 内存共分为虚拟机栈,堆,方法区,程序计数器,本地方法栈五个部分。

程序计数器(线程私有):(记录每个执行线程的指令地址) 是当前线程锁执行字节码的行号治时期,每条线程都有一个独立的程序计数器,这类内存也称为“线程私有”的内存。正在执行java方法的话,计数器记录的是虚拟机字节码指令的地址(当前指令的地址)。如果是Natice方法,则为空。

java 虚拟机栈(每个执行线程私有的,对指令的执行) 也是线程私有的。 每个方法在执行的时候也会创建一个栈帧,存储了局部变量,操作数,动态链接,方法返回地址。 每个方法从调用到执行完毕,对应一个栈帧在虚拟机栈中的入栈和出栈。 通常所说的栈,一般是指在虚拟机栈中的局部变量部分。 局部变量所需内存在编译期间完成分配, 如果线程请求的栈深度大于虚拟机所允许的深度,则StackOverflowError。 如果虚拟机栈可以动态扩展,扩展到无法申请足够的内存,则OutOfMemoryError。

本地方法栈(线程私有)(用于执行native方法) 和虚拟机栈类似,主要为虚拟机使用到的Native方法服务。也会抛出StackOverflowError 和OutOfMemoryError。

Java堆(线程共享)(由于创建对象实例,方法栈的创建对象的值为这个对象的地址) 被所有线程共享的一块内存区域,在虚拟机启动的时候创建,用于存放对象实例。 对可以按照可扩展来实现(通过-Xmx 和-Xms 来控制) 当队中没有内存可分配给实例,也无法再扩展时,则抛出OutOfMemoryError异常。

方法区(线程共享)(加载的类和常量) 被所有方法线程共享的一块内存区域。 用于存储已经被虚拟机加载的类信息,常量,静态变量等。 这个区域的内存回收目标主要针对常量池的回收和堆类型的卸载。

内存溢出和内存泄漏 多线程执行,创建过多的对象;一次从数据库查询大量的数据

while条件的使用,不断得创建对象,不没有被消费的掉, 存在大量的生命周期过长的对象

程序的递归出现栈内存的溢出 创建的线程数过多,导致本地线程内存溢出 数据存储的数量超量

比如下面的代码,这里的object实例,其实我们期望它只作用于method1()方法中,且其他地方不会再用到它,但是,当method1()方法执行完成后,object对象所分配的内存不会马上被认为是可以被释放的对象,只有在Simple类创建的对象被释放后才会被释放,严格的说,这就是一种内存泄露。(使用完,主动释放)

内存泄露:指程序中动态分配内存给一些临时对象,但是对象不会被GC所回收,它始终占用内存。即被分配的对象可达但已无用。 内存溢出:指程序运行过程中无法申请到足够的内存而导致的一种错误。内存溢出通常发生于OLD段或Perm段垃圾回收后,仍然无内存空间容纳新的Java对象的情况。 从定义上可以看出内存泄露是内存溢出的一种诱因,但是不是唯一因素

对象的生命周期

linux如何排查jvm的堆栈信息 2、查询进程信息

#查询占用内存的进程(shift+m排序) top #存活的对象占用内存前100排序 jmap -histo:live 41843 | head -n 100 3、查询进程里面详细信息 jmap -heap 41843