Notes about JVM

不得不说,特么这兄弟归纳的太好了地址

字符串常量池

内存结构

旧的图

更特么详细的 上面的线程共享区,因为所有对象都在这里分配内存,所以也是GC的主要区域

堆结构

关于堆结构,上图是JDK8的示意图 ###堆

新生代:

所有新生成的对象首先都是存放在新生代

Eden区

最主要包含了刚创建的对象,该区域对象大部分都是短期内死亡,所以垃圾回收器主要用标记-整理算法回收该区域

Survivor区

又分为平等的两个区:

  1. From Survivor(s0)
  2. To Survivor(S1) 采用复制算法,每次只使用其中一块;

Eden:Survivor=8:1

老年代

一般在Survivor中没有被清除出去的对象才会进入该区域,主要使用标记-清除(mark-sweep)算法

操作

可-Xms 数字或-Xmx 数字 两个jvm参数来指定一个程序的堆内存大小,第一个是起始值,第二个是最大值

java -Xms1M -Xmx2M helloworld

方法区(method area)

用于存放已被加载的类信息,常量,静态变量,即时编译器编译(jit)后的代码等 然而对其进行垃圾回收的话主要是对常量池和类的卸载

Hotspot虚拟机把它当作永久代进行垃圾回收,但因为很少确定永久代的大小 JDK1.8开始,把永久代移除,并把方法区移至元空间(位于本地内存,不是JVM内存)

运行时常量池

是方法区一部分,Class文件中的常量池(编译器生成的各种字面量和符号引用)会在类加载后被放入这个区域 除了在编译期生成的常量,还允许动态生成,如string.Intern() PS:

  1. 用双引号声明出来的String对象会被存储在常量池里
  2. 如果不是用双引号,intern方法会从字符串常量池中查询字符串是否存在,如果不存在就会将当前字符串放入常量池
常见面试题
String s=new String("abc");

如上创建了多少个对象? 答案就是2个,一个是String在堆上的对象,一个是常量池里面的字符串”abc“

操作

-XX:PermSize最小空间 -XX:MaxPermSize最大空间

异常

和heap一样不需要连续的内存,而且动态扩展,失败会抛出OutOfMemory异常

JVM stack

每个Java方法在执行的同时会创建一个栈帧用于存储局部变量表,操作数栈,常量池引用等信息; 从调用到执行完成的过程,就对应了一个栈帧在jvm栈中的入栈和出栈

操作

可以通过 -Xss 设置jvm栈大小

java -Xss512M helloworld

异常

当请求栈深度超过最大值,会抛出stackoverflow异常

本地方法栈

本地方法栈与JVM栈类似,只不过JVM栈为java方法(字节码)服务,本地方法为JVM的native方法服务 本地方法一般由c++,汇编等编写

操作

Sun jdk中和jvm栈和本地方法栈是同一个,因此也可以用-Xss控制每个线程的大小

程序计数器

记录正在执行的虚拟机字节码指令的地址(如果正在执行的是本地方法则为空)


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!