java 的内存分配,不懂内存,与高级工程师无缘!
不少的程序员,一直在 COPY。其实也想写出牛叉的代码,成为一名牛叉的软件工程师。却不知成为牛叉的程序员第一步就是搞懂内存分配。
在实际编程中,每运行一个java程序会产生一个 java 进程,每个 java 进程可能包含一个或者多个线程,每一个 Java 进程对应唯一一个JVM实例,每一个 JVM 实例唯一对应一个堆,每一个线程有一个自己私有的栈。进程所创建的所有类的实例(也就是对象)或数组(指的是数组的本身,不是引用)都放在堆中, 并由该进程所有的线程共享。Java 中分配堆内存是自动初始化的,即为一个对象分配内存的时候,会初始化这个对象中变量。虽然 Java 中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在栈中分配, 也就是说在建立一个对象时在堆和栈中都分配内存,在堆中分配的内存实际存放这个被创建的对象的本身,而在栈中分配的内存只是存放指向这个堆对象的引用而已。局部变量new出来时,在栈空间和堆空间中分配空间,当局部变量生命周期结束后,栈空间立刻被回收,堆空间区域等待 GC 回收。
具体的概念:JVM 的内存可分为 3 个区:堆 (heap)、栈 (stack) 和方法区(method,也叫静态区):
堆区:
1. 存储的全部是对象,每个对象都包含一个与之对应的 class 的信息 (class 的目的是得到操作指令) ;
2.jvm 只有一个堆区 (heap),且被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身和数组本身;
北京博雅环球专注云计算,大数据,人工智能,详情:http://www.byhq-edu.com/
栈区:
1. 每个线程包含一个栈区,栈中只保存基础数据类型本身和自定义对象的引用;
2. 每个栈中的数据 (原始类型和对象引用) 都是私有的,其他栈不能访问;
3. 栈分为 3 个部分:基本类型变量区、执行环境上下文、操作指令区 (存放操作指令);
方法区(静态区):
1. 被所有的线程共享,方法区包含所有的 class(class 是指类的原始代码,要创建一个类的对象,首先要把该类的代码加载到方法区中,并且初始化)和static 变量。
2. 方法区中包含的都是在整个程序中永远唯一的元素,如 class,static 变量。
北京博雅环球专注云计算,大数据,人工智能,详情:http://www.byhq-edu.com/
北京博雅环球专注云计算,大数据,人工智能,详情:http://www.byhq-edu.com/
运行该程序时,首先启动一个Java 虚拟机进程,这个进程首先从classpath中找到 AppMain.class 文件,读取这个文件中的二进制数据,然后把 Appmain 类的类信息存放到运行时数据区的方法区中,这就是 AppMain 类的加载过程。
接着,Java 虚拟机定位到方法区中 AppMain 类的 Main 方法的字节码,开始执行它的指令。这个 main 方法的第一条语句就是:
**Sampletest1=newSample("测试 1");
**
该语句的执行过程:
1、 Java 虚拟机到方法区找到 Sample 类的类型信息,没有找到,因为 Sample 类还没有加载到方法区(这里可以看出,java 中的内部类是单独存在的,而且刚开始的时候不会跟随包含类一起被加载,等到要用的时候才被加载)。Java 虚拟机立马加载 Sample 类,把 Sample 类的类型信息存放在方法区里。
2、 Java 虚拟机首先在堆区中为一个新的 Sample 实例分配内存, 并在 Sample 实例的内存中存放一个方法区中存放 Sample 类的类型信息的内存地址。
3、 JVM 的进程中,每个线程都会拥有一个方法调用栈,用来跟踪线程运行中一系列的方法调用过程,栈中的每一个元素就被称为栈帧,每当线程调用一个方法的时候就会向方法栈压入一个新帧。这里的帧用来存储方法的参数、局部变量和运算过程中的临时数据。
4、位于“=”前的 Test1 是一个在 main 方法中定义的一个变量(一个 Sample 对象的引用),因此,它被会添加到了执行 main 方法的主线程的JAVA方法调用栈中。而“=”将把这个 test1 变量指向堆区中的 Sample 实例。
5、JVM 在堆区里继续创建另一个 Sample 实例,并在 main 方法的方法调用栈中添加一个 Test2 变量,该变量指向堆区中刚才创建的 Sample 新实例。
6、JVM依次执行它们的 printName 方法。当 JAVA 虚拟机执行 test1.printName 方法时,JAVA 虚拟机根据局部变量test1持有的引用,定位到堆区中的 Sample 实例,再根据 Sample 实例持有的引用,定位到方法去中Sample类的类型信息,从而获得 printName 方法的字节码,接着执行 printName 方法包含的指令,开始执行。
挑战高薪!从博雅开始!
150 天 0 基础到精通,资深教师团队 + 配备高级服务器 + 军事化管理模式,采取纯小班面授,入学签订就业协议,保障薪资 8K-30K,数百家企业合作,无缝对接!