《Java 底层原理》Java内存模型

前言

通过JDK原理来重新理解一遍Java内存模型,通过其他方式学习到,总会有错误或者遗漏的情况。

内存模型

Java常常被提到的4个概念:

class文件:硬盘上的.class文件

class content:类加载器将.clas文件加载入内存,存储字节码文件数据的那块内存区域

Class对象:Class clazz = Test.class;

Java对象 new关键字或者其他方式产生的实体对象:例如 Test obj = new Test();

Java内存结构图:

1. 方法区:JDK8及之后通过元空间实现,元空间使用的OS内存,存放的内容为:类名,方法名,属性名,变量名,static 等等

2. 本地方法栈:JNI,Java调用c++方法的链接库,Java native方法的调用。

3. 虚拟机栈:一个线程一个虚拟机栈,一个虚拟机栈里面方法调用的次数个栈帧。

        栈帧包含:

    局部变量:方法里面的变量信息(int a = 0; int b = 1 这类信息的a 和 b 信息记录的地方)。

              操作数栈:方法里面的 a+b , a = 4,等等这类操作的信息。

              动态链接:mian方法对应的Jvm对象在元空间的内存地址。

              返回地址:保存现场,保存上一个方法的调用完这个方法(test)的下一个程序计数器,保证后续方法执行完成之后,后面的代码可以继续执行。

              附加信息:

        JVM运行test方法,内部是怎么做的?

                第一步、创建test的方法的栈帧

                第二步、在test方法的栈帧中保存上一个方法的字节码的下一行程序计数器(比如:21)

                第三步、线程的局部表开始指针(上一个方法的)保存至add方法的栈帧

                第四步、线程的操作数栈开始指针(上一个方法的)保存至add方法的栈帧, 1,2,3这3步表示保存现场。

                第五步、将test方法的局部表指针赋值给线程的局部表指针

                第六步、将test方法的操作数栈指针赋值给线程的操作数栈指针

4. 程序计数器:字节码的索引(EIP,RIP)

Java 各个内存之间的引用关系

  • 虚拟机栈指向方法区:动态链接,例如:test.mian()方法。
  • 虚拟机栈指向堆区:对象的引用变量,例如:Test obj = new Test();
  • 方法区指向堆区:引用类型的静态属性,例如static Test = new Test(),Test在堆区,static 在方法区。
  • 堆区指向方法区:对象的内存布局Klass的信息部分存在方法区。

Jvm 源码中的内存分布:(Cheap,ValueObj,AllStatic)

class CHeapObj {
 public:
  void* operator new(size_t size) throw();
  void  operator delete(void* p);
  void* new_array(size_t size);
};


// Base class for objects used as value objects.
// Calling new or delete will result in fatal error.

class ValueObj {
 public:
  void* operator new(size_t size) throw();
  void operator delete(void* p);
};

// Base class for classes that constitute name spaces.

class AllStatic {
 public:
  void* operator new(size_t size) throw();
  void operator delete(void* p);
};

总结

学习内存结构,就是为了解决我们工作的问题。

posted @ 2021-02-07 09:35  加速丨世界  阅读(142)  评论(0编辑  收藏  举报