最简单的JVM内存结构图
JVM内存结构图

大家好,好几天没有更新了,今天的内容有点多,我们详细介绍下JVM内部结构图,还是和之前一样,
/**
* @author :jiaolian
* @date :Created in 2021-03-10 21:28
* @description:helloworld测试jvm内存区域
* @modified By:
* 公众号:叫练
*/
public class HelloWorldTest {
public static void main(String[] args) {
//新建HelloWorldTest对象;
HelloWorldTest helloWorldTest = new HelloWorldTest();
//新建2个线程调用sayHello
for (int i=0; i<2; i++) {
new Thread(()->helloWorldTest.sayHello("world")).start();
}
}
/**
* 对某人说hello
* @param who
*/
public void sayHello(String who) {
System.out.println(Thread.currentThread().getName()+"hello!"+who);
}
}
如上代码:在主线程中for循环新建2个线程调用sayHello,最后两个线程分别对世界问好!这段代码比较好理解,就不贴输出结果了。我们编写并运行了这段代码,我们主要看看这段代码在JVM中是怎么运作的。
首先,我们编写一个HelloWorldTest.Java文件,经过javac编译会转化成字节码HelloWorldTest.class,为什么要转化成字节码呢?因为Java虚拟机能识别!最后由类加载子系统ClassLoader将字节码装载到内存。每块内存各有自己的作用,最后由执行引擎来执行字节码。下面我们重点介绍下各块内存发挥的作用!

方法区
方法区主要装一些静态信息,比如:类元数据,常量池,方法信息,类变量等。如上代码HelloWorldTest.class是类元数据,sayHello,main都是方法信息等都是放在方法区存储的。方法区中还需要注意两点:
堆
堆中主要存放实例对象。你可以这么理解,只要看到用关键字

在堆内存中,内存需要划分成两块区域,
对堆分块原因是方便JVM

栈
栈内存空间相对于堆空间比较小,也属于线程私有,栈中主要是一堆栈帧,是先进后出的,理解起来栈帧对应就是一个方法,方法中包含局部变量,方法参数,还有方法出口,访问常量指针,和异常信息表,其中异常信息表和常量指针信息我们在方法体中可能看不出来,但通过工具

一个线程可能对应多个栈帧,栈帧都是从

程序计数器
程序计数器也是线程独享的,多线程执行程序依赖于

本地方法栈
本地方法栈就不过多介绍了,和栈结构一样,是一块独立的区域,只是对应的是native方法。
直接内存
直接内存独立于JVM内存之外的内存,可以直接和NIO接口交互,NIO接口会频繁操作内存,如果放在JVM管理,无疑会增加JVM开销,所以单独将这块提出来,而且直接内存操作数据相比较JVM更快,显而易见提升了程序性能。
内存分配性能优化-逃逸分析
我们之前说过,只要是看到关键字new,
/**
* @author :jiaolian
* @date :Created in 2021-03-10 16:10
* @description:逃逸分析测试
* @modified By:
* 公众号:叫练
*/
public class EscapeTest {
//private static Object object;
public static void alloc() {
//一个对象相当于16k大小,非逃逸对象
//object = new Object();
Object object = new Object();
}
public static void main(String[] args) throws InterruptedException {
//亿次内存
long begin=System.currentTimeMillis();
for (int i=0; i<10000000; i++) {
alloc();
}
long end=System.currentTimeMillis();
System.out.println("time:"+(end-begin));
}
}
如上代码,我们在主函数里面通过for循环1亿次来new Object,一个object为16k,大致估算下有GB数据了,此时我们手动配置JVM参数,-XX:+PrintGC -Xmx10M -XX:+DoEscapeAnalysis;设置打印GC信息,默认最大的堆内存是10M。
执行程序,打印结果如下图所示。一共进行了3次GC,

原因分析:
观察我们上述案例代码中alloc()方法,方法中Object object = new Object();object是一个局部变量,每次新建后到下一次循环再新建,上一次新建的对象就会出栈,object引用指向的对象就会失效,失效的对象就会被GC回收了。开启逃逸分析后,new Object()创建的对象就不在堆上分配空间了,而放到了栈上。这就是JVM通过逃逸分析对内存的优化。思考下,如果将private static Object object;注释放开,object还会是非逃逸对象吗?
注意:逃逸对象不能在栈上分配空间!
相信到这里你已经对
总结
好了,写的有点累了,写的不全同时还有许多需要修正的地方,希望亲们加以指正和点评,喜欢的请点赞加关注哦。
