一,程序内存管理:
在这里,我们要引出三个组件:Java 程序,Java 虚拟机与操作系统。Java
程序运行需要 JVM,JVM 又与操作系统交互获取内存或者释放内存。这里我们重点掌握三者之间使用分配内存的相互关系。我们从程序运行前,程序运行开始,与程序运行内存溢出三个阶段讲解。
程序运行前:有些编程语言编写的程序会直接向操作系统请求内存,但 Java并不支持那么做。当程序准备执行时,由 JVM 向操作系统请求一定的内存空间,称为初始内存空间。程序执行过程中所需的内存都由 Java 虚拟机从这片内存空间中划分。这样做的一个重要优点是保证了程序的平台无关性。 如下图:
程序运行中:Java 程序一直向 Java 虚拟机申请内存,当程序所需内存空间超出初始内存空间时,Java 虚拟机会再次向操作系统申请更多的内存供程序使用。
内存溢出:程序接着运行,当 Java 虚拟机已申请的内存达到了规定的最大
内存空间,但程序还需要更多的内存,这时会出现内存溢出的错误。
至此可以看出,Java 程序所使用的内存是由 Java 虚拟机进行管理、分配的。
Java 虚拟机规定了 Java 程序的初始内存空间和最大内存空间,开发者只需要关心 Java 虚拟机是如何管理内存空间的,而不用关心某一种操作系统是如何管理内存的。
二:内存空间逻辑划分:方法区,堆与栈
对于大多数人来说,我们经常喜欢把Java内存分为堆,栈和方法区
1.方法区:
方法区的内存我们在程序开发中关注较少。java 中需要占用内存的,除去
变量外,其实还有一个重要的东西就是类结构,比如我们开发了一个 Student类,那么在创建 Student 对象之前,JVM 类加载器会把 Student 类加载到内存,称为类结构(或者叫模板),当我们创建对象时,使用这个类结构类模板。方法区默认最大容量为 64M,
方法区主要存储:类的结构,静态属性与静态方法。编写中小型程序时,一般不会造成方法区的内存溢出。
2.堆:
堆默认最大容量为 64M,堆存放对象持有的数据,同时保持对原类的引用。可以简单的理解为对象属性的值保存在堆中,对象调用的方法保存在方法区。
3.栈
栈默认最大容量为 1M,在程序运行时,每当遇到方法调用时,Java 虚拟机
就会在栈中划分一块内存称为栈帧(Stack frame),栈帧中的内存供局部变量(包括基本类型与引用类型)使用,当方法调用结束后,Java 虚拟机会收回此栈帧占用的内存。也就是说:栈中主要存储8种基本数据类型以及对象的引用(即指向堆内存的地址)如图:
三:但实际上,这种分发很粗糙,Java内存的划分远比这复杂,如图.
1.程序计数器:
程序计数器是一块较小的内存空间,字节码解释器就是通过它来选取需要执行的字节码指令,内存私有(即每个线程之间的计数器互不影响,独立存储),这样设计师为了解决多线程在切换后能恢复的确认位置而设立的,因为Java虚拟机的多线程是通过轮流切换并分配处理器实现的
2.Java虚拟机栈
此块区域也是线程私有的它的生命周期与线程相同,每个java方法在执行时都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息.而上面所提到的栈即是此java虚拟机栈,更确切的说是虚拟机栈中的局部变量表部分,
主要存储8种基本数据类型以及对象引用
3.本地方法栈:
与虚拟机栈发挥的作用很相似,但也是有区别的,虚拟机栈为虚拟机执行java方法服务,而本地方法栈为虚拟机使用native方法服务.因为其余java虚拟机很相似,故以有的虚拟机直接将本地方法栈和Java虚拟机栈合二为一(l例如:Sun HotSpot虚拟机)
4.java堆
java堆是被所有线程共享的一块区域,在虚拟机启动是创建,它存在的唯一目的就是存放对象几乎所有对象实例都在此分配内存,(在此可了解一下JIT)另外,java堆是垃圾回收车管理的主要区域,(其实由于收集器基本都采用分代收集算法,致使java堆还可继续细分:新生代和老生代),
5方法区:
线程共享区域,它用于,存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据,垃圾回收区域在这块较少出现,此区域内存回收的主要目标是针对常量池的回收和对类型的卸载
6.运行时常量池
它是方法区的一部分,此区域主要用来存放编译器生成的各种字面量和符号引用,一般来说,Class文件中翻译出来的直接引用也会存储在此,字面量和符号引用是什么呢?
- 字面量包括:1.文本字符串 2.八种基本类型的值 3.被声明为final的常量等;
字面量也可以理解为实际值,int a = 8
中的8和String a = "hello
“中的hello都是字面量 - 符号引用包括:1.类和方法的全限定名2.字段的名称和描述符 3.方法的名称和描述符。
符号引用就是一个字符串,这个字符串包含足够的信息,以供实际使用时可以找到相应的位置。你比如说某个方法的符号引用,如:“java/io/PrintStream.println:(Ljava/lang/String;)”。里面有类的信息,方法名,方法参数等信息。
7.直接内存
并不是虚拟机运行时数据区的一部分,但它却被频繁的使用,且很可能导致OutOfMemory异常!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/96906.html