本节小汪重点介绍下java内存,首先提问:
1.jvm内存如何分配
2.为什么要划分新生代和老年代,实践中究竟哪些属于新哪些属于旧
3.简要介绍一下jstat -gc 如何
1.jvm内存如何分配
1.1概念介绍
内存分为堆栈两部分
栈:线程私有
堆:线程共享
栈:
程序计数器:当前线程所执行的字节码行号指示器 控制代码字节的执行
java虚拟机栈:描述的是java方法执行的内存模型,方法从调用到完成就对应一个栈帧在虚拟机栈中入栈到出栈的过程。
栈帧:一种数据结构 用于存储局部变量、操作数栈、动态链接、方法出口
本地方法栈:为虚拟机栈的Native方法服务
堆:
Java堆:存java对象实例
方法区(Non-Heap,永久代):常量、静态变量、类信息
运行时常量池:方法区的一部分,编译期的字面量和符号引用
1.2下面通过代码实例来加深认识
public class MyThreadPrinter2 implements Runnable {
private String name;
private Object prev;
private Object self;
private static int num = 12;
private MyThreadPrinter2(String name, Object prev, Object self) {
this.name = name;
this.prev = prev;
this.self = self;
}
@Override
public void run() {
int count = 10;
System.out.println(count);
}
public static void main(String[] args) throws Exception {
Object a = new Object();
Object c = new Object();
MyThreadPrinter2 pa = new MyThreadPrinter2("A", c, a);
new Thread(pc).start();
}
}
该代码产生了对象和线程,并执行该线程,下面分析一下当main方法执行时jvm内存情况
1.
Object a = new Object();
Object c = new Object();
Java堆里会产生两个Object对象
栈里本地变量表产生两个reference类型 a和c 分别引用了堆中的两个对象实例
2.
MyThreadPrinter2 pa = new MyThreadPrinter2("A", c, a);
Java堆中产生一个MyThreadPrinter2对象 对象中包含了name prev self这几个变量
同时静态num被保存到了方法区中
栈里本地变量表产生pa并指向MyThreadPrinter2对象
run方法信息有关的字面量会保存在方法区中
3.
new Thread(pc).start();
产生一个线程对象 并调用run方法
在栈中会针对该线程对象产生相应栈帧
4.
public void run() {
int count = 10;
System.out.println(count);
}
run方法中的本地变量表会生成一个count并赋值为10
最终该方法的运行会通过指令集对栈帧进行出栈操作并计算来完成。
2.为什么要划分新生代和老年代,实践中究竟哪些属于新哪些属于旧
从内存回收的角度 java堆分为新生代、老年代、永久代
永久代:方法区的内容放在这里
新生代:首次生成的对象或数组
老年代:首次生成的大对象或经过N次垃圾回收后仍存活的对象
每次回收老年代也会回收永久代
3.jstat gc 介绍
究竟内存如何分配的 我们可以使用jstat gc来查看
可以看到新生代有三块区域 Eden Survivor 对象首先分配到Eden 等Eden满了会进行收集然后幸存的放入Survivor
老年代Old
永久代Perm