jvm内存模型
根据JVM规范,JVM 内存共分为虚拟机栈,堆,方法区,程序计数器,本地方法栈五个部分。
程序计数器(线程私有):
是当前线程锁执行字节码的行号治时期,每条线程都有一个独立的程序计数器,这类内存也称为“线程私有”的内存。正在执行java方法的话,计数器记录的是虚拟机字节码指令的地址(当前指令的地址)。如果是Natice方法,则为空。
java 虚拟机栈(线程私有):
每个方法在执行的时候会创建一个栈帧,存储了局部变量,操作数,动态链接,方法返回地址。
每个方法从调用到执行完毕,对应一个栈帧在虚拟机栈中的入栈和出栈。
通常所说的栈,一般是指在虚拟机栈中的局部变量部分。
局部变量所需内存在编译期间完成分配,
如果线程请求的栈深度大于虚拟机所允许的深度,则StackOverflowError。
如果虚拟机栈可以动态扩展,扩展到无法申请足够的内存,则OutOfMemoryError。
本地方法栈(线程私有):
和虚拟机栈类似,主要为虚拟机使用到的Native方法服务。也会抛出StackOverflowError 和OutOfMemoryError。
堆(线程共享):
被所有线程共享的一块内存区域,在虚拟机启动的时候创建,用于存放对象实例。
对可以按照可扩展来实现(通过-Xmx 和-Xms 来控制)
当队中没有内存可分配给实例,也无法再扩展时,则抛出OutOfMemoryError异常。
方法区(线程共享)JDK1.8已经去掉了方法区:
被所有方法线程共享的一块内存区域。
用于存储已经被虚拟机加载的类信息,常量,静态变量等。
这个区域的内存回收目标主要针对常量池的回收和堆类型的卸载。
堆和栈的区别
1)堆和栈功能上的区别
- 以栈帧的方式存储方法调用的过程,并存储方法调用过程中基本数据类型的变量(int、short、long、byte、float、double、boolean、char等)以及对象的引用变量,其内存分配在栈上,变量出了作用域就会自动释放;
- 而堆内存用来存储Java中的对象。无论是成员变量,局部变量,还是类变量,它们指向的对象都存储在堆内存中;
2)堆和栈在线程共享和线程私有区别
- 栈内存归属于单个线程,每个线程都会有一个栈内存,其存储的变量只能在其所属线程中可见,即栈内存可以理解成线程的私有内存。
- 堆内存中的对象对所有线程可见。堆内存中的对象可以被所有线程访问。
1.栈:方法运行时进入的内存,里面还会存储程序的局部变量
2.堆:new出来的对象都在堆内存,存放着成员方法地址的引用,堆内存中的数据都会有默认的初始值。
3.方法区:用来存放.class字节码对象,字节码文件加载时所进入的内存
在1.7中,jvm分为三个区,年轻代,老年代,永久代
年轻代中有Eden区和两个大小相等的suivivor区,survivor一般用来存放new出来的对象,
当年轻代中new对象经过一系列垃圾回收仍然存活的就会被jvm放入老年代,
在永久代中一般用来存放字节码class,method,filed对象
在1.8中去除了永久代,由于永久代内存经常不够使用,爆出异常,
基于此将永久区废除,改为元空间,使用本地内存空间。
查看Java进程命令
1.jinfo -flag <进程id>
2.jinfo -flag <参数名> <进程id>
3.通过jps或者jps -l 查看java进程