《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);
};

总结

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

《Java 底层原理》Java内存模型 相关文章

【Java-GUI】06 绘图 Part2 位图处理

绘画程序案例: 原视频排错找了半天,原来是变量名的问题 package cn.dzz;import java.awt.*;import java.awt.event.*;import java.awt.image.BufferedImage;public class Sketchpad { // 窗体对象 private Frame frame = new Frame(); // 画板宽高 private

Java对象头详解

由于Java面向对象的思想,在JVM中需要大量存储对象,存储时为了实现一些额外的功能,需要在对象中添加一些标记字段用于增强对象功能,这些标记字段组成了对象头。 1.对象头形式 JVM中对象头的方式有以下两种(以32位JVM为例): 1.1.普通对象 |-------------

Java-线程

目录 1.线程与进程 进程 线程 区别 2.线程的生命周期 3.创建线程 继承Thread类 实现Runnable接口 关系 关于两种创建线程方法,资源是否共享说法的一点理解 问题:启动一个线程使用run()还是start()方法 1.线程与进程 操作系统中运行的程序,就是一个进程。而

Java同步组件之CountDownLatch,Semaphore

Java同步组件概况 CountDownLatch : 是闭锁,通过一个计数来保证线程是否一直阻塞 Semaphore : 控制同一时间,并发线程数量 CyclicBarrier:字面意思是回环栅栏,通过它可以实现让一组线程等待至某个状态之后再全部同时执行。 ReentrantLock:是一个重入锁,一个线

嘿你要的Java内存模型(JMM)来了!

1、 计算机的硬件内存结构 2、 Java内存模型的背景和定义 3、 Java内存模型 3.1 主内存、工作内存的定义 3.2 内存的交互操作 3.3 JMM缓存不一致问题 4、 Java内存模型的实现 在学习Java内存模型(JMM)前,我们先了解下计算机的硬件内存结构,因为JMM结构就是

Java随机数-for循环-Scanner-Switchcase

从键盘获取值 java.util.Scanner input = new java.util.Scanner(System.in); java.util.Scanner:是一个扫描仪的类型,是引用数据类型,首字母是大写, 其中java.util是包 input是一个变量名,他表示这个扫描仪 new java.util.Scanner(System.in)是给input

Java运算符-if分支语句

运算符 // 除号:/int num1 = 12;int num2 = 5;int result1 = num1 / num2;System.out.println(result1); //2double result2 = num1 / num2;System.out.println(result2); //2.0double result3 = num1 / num2 + 0.0;System.out.println(result3); //2.0doubl

JavaScript作用域与作用域链

JavaScript作用域 在JavaScript中,变量的作用域有全局作用域和局部作用域两种 1. 全局作用域(Global Scope) 在代码中任何地方都能访问到的对象拥有全局作用域,一般来说以下几种情形拥有全局作用域: (1)最外层函数和在最外层函数外面定义的变量拥有全

Java04:运算符拓展,Javadoc

Java04:运算符拓展,Javadoc 自增自减运算符 ++ -- 自增,自减 一元运算符 ina a = 3; int b = a++;//执行完这行代码后,先给b赋值,在自增int c = ++a;//执行完这行代码前,先自增,再给b赋值 位运算符 A = 0011 1100 B = 0000 1101 AB = 0000 1100 A|B =

Js中的位操作符

Js中的位操作符 JavaScript 的数字类型为双精度 IEEE 754 64 位浮点类型,但是在位运算中位运算符用于 32 位的数字上, 任何的数字操作都将转为 32 位, 运算结果再转化为 Js 数字类型。 描述 所有的按位操作符的操作数都会被转成补码形式的有符号 32 位整数,