1、简述一下JVM的内存结构?
JVM在执行Java程序时,会把它管理的内存划分为若干个的区域,每个区域都有自己的用途和创建销毁时间。如下图所示,可以分为两大部分,线程私有区和共享区。
线程私有区:
① 程序计数器
-
作用:是一块较小的内存空间,可以理解为是当前线程所执行程序的字节码文件的行号指示器,存储的是当前线程所执行的行号
-
特点:线程私有 ,唯一一个不会出现内存溢出的内存空间
② 虚拟机栈
-
作用:管理JAVA方法执行的内存模型。每个方法执行时都会创建一个桢栈来存储方法中变量的变量表、操作数栈、动态链接方法、返回值、返回地址
等信息。栈的大小决定了方法调用的可达深度(递归多少层次,或嵌套调用多少层其他方法,-Xss参数可以设置虚拟机栈大小)
-
特点:
1、线程私有
2、局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)以及对象引用(reference 类型)
3、栈太小方法调用过深,将抛出StackOverflowError异常
③ 本地方法栈:与虚拟机栈作用相似。但它不是为Java方法服务的,而是本地方法(C语言)。由于规范对这块没有强制要求,不同虚拟机实现方法不同。
线程共享区:
① 堆内存
-
作用:是Java内存区域中一块用来存放对象实例的区域,新创建的对象,数组都使用堆内存;【从Java7开始,常量池也会使用堆内存】
Java 堆从GC的角度还可以细分为: 新生代( Eden区 、From Survivor区和 To Survivor区 )和老年代。
-
特点:
1、被线程共享,因此需要考虑线程安全问题
2、会产生内存溢出问题
-
虚拟机参数:
-Xms 设置最小堆内存大小(不能小于1024K); -Xms 堆内存初始大小,可以通过jmap工具进行查看
-Xmx 设置最大堆内存大小(不能小于1024K); -Xmx 堆内存最大值,可以通过jmap工具进行查看
例如:-Xms1024K -Xmx2048K
注意:
② 方法区
-
作用:它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
-
特点:
1、方法区是一块线程共享的内存区域
2、方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出的错误
3、jdk1.6和jdk1.7方法区也常常被称之为永久区(永久代),大小一般都是几百兆;
4、jdk1.8已经将方法区取消,替代的是元数据区(元空间),如果不指定大小,默认情况下,虚拟机会耗尽可用系统内存
5、jdk7以后就将方法区中的常量池移动至堆内存
变化的原因:
1、提高内存的回收效率(方法区内存的回收效率远远低于堆内存,因为方法去中存储的都是类信息,静态变量...这些信息不能被轻易回收)
2、字符串常量池在方法区,那么很容易产生内存溢出(因为方法区的垃圾回收效率比较低);