1.类加载子系统:负责从文件系统或者网络中加载Class的信息,加载的信息存放在一块称之为方法区的内存空间
2.方法区:就是存放类信息,常量信息,常量池信息,包含字符串字和数字常量等
3.java堆:在Java虚拟机启动的时候建立java堆,它是java程序最主要的内存工作区域,几乎所有对象的实力都存放在java堆中,堆空间是所有线程共享的。
它是JVM用来存储对象实例以及数组值的区域,可以认为Java中所有通过new创建的对象的内存都在此分配,Heap中的对象的内存需要等待GC进行回收。
(1) 堆是JVM中所有线程共享的,因此在其上进行对象内存的分配均需要进行加锁,这也导致了new对象的开销是比较大的
(2) Sun Hotspot JVM为了提升对象内存分配的效率,对于所创建的线程都会分配一块独立的空间TLAB(Thread Local Allocation Buffer),其大小由JVM根据运行的情况计算而得,在TLAB上分配对象时不需要加锁,因此JVM在给线程的对象分配内存时会尽量的在TLAB上分配,在这种情况下JVM中分配对象内存的性能和C基本是一样高效的,但如果对象过大的话则仍然是直接使用堆空间分配
(3) TLAB仅作用于新生代的Eden Space,因此在编写Java程序时,通常多个小的对象比大的对象分配起来更加高效。
(4) 所有新创建的Object 都将会存储在新生代Yong Generation中。如果Young Generation的数据在一次或多次GC后存活下来,那么将被转移到OldGeneration。新的Object总是创建在Eden Space。
4.直接内存:java的NIO库允许java程序使用直接内存,从而提高性能,通常直接内存速度由于Java堆。
5.每个虚拟机线程都有一个私有的栈,一个线程的Java栈在线程创建的时候被创建,java栈中保存着局部变量 方法参数 同时Java的方法调用 返回值等等。
(java中定义的八种基本类型:boolean、char、byte、short、int、long、float、double)、部分的返回结果以及Stack Frame,非基本类型的对象在JVM栈上仅存放一个指向堆上的地址。
6.本地方法栈和Java 栈非常类似,最大不同本地方法栈用于本地方法调用,java虚拟机允许Java直接调用本地方法
7.垃圾收集系统事Java的核心,开发人员无需手工清理,java有自己一套进行垃圾清理的机制
8.PC寄存器是每个线程私有的空间,java虚拟机会为每个线程创建PC寄存器,在任意时刻,一个java线程总是在执行一个方法,这个方法被称为当前方法,如果当前方法不是本地方法,PC寄存器就会执行当前正在被执行的指令,如果是本地方法,则PC寄存器值为undefined,寄存器存放如当前执行环境指针,程序计数器,操作栈指针等
9.虚拟机最核心的组件就是执行引擎了,它负责执行虚拟机的字节码,一般用户先及逆行编译成机器码后执行
堆 栈 方法区概念和联系
堆解决的事数据存储的问题,即数据怎么放,放在哪
栈解决程序的运营问题,即程序如何执行,如何处理数据
方法区则是辅助堆栈的永久区,解决堆栈信息的产生,是先决条件。
比如我 我们创建一个新的对象,User:那么User类的一些信息(类信息,静态信息都存在于方法区中)
而User类被实例化出来之后,被存储到Java堆中,一块内存空间 当我们去使用的时候,都是使用User对象的引用,如User user=new User();
这里的user就是存放在Java栈中的,即User真实对象的一个引用
java堆和java应用程序关系最密切的内存空间,几乎所有对象都存放在其中,并且Java堆完全是自动化管理的,通过垃圾回收机制,垃圾对象会自动清理,不需要显示地释放
根据垃圾回收机制不同,java堆有可能拥有不用的结构,最为常见的将整个Java堆分为新生代和老年代。
新生代分为eden区,s0区,s1区 ,s1和s0也被称为to和from区域,他们是两块大小相等并且可以互换角色的空间。
绝大多数情况下,对象先分配在eden区,在一次新生代回收后,如果对象还存活,则会进入s0或s1区,之后每经过一次新生代回收,如果对象存活则他的年龄就加1,当对象达到一定年龄后,则进入老年代。(s0 和 s1 采用复制算法 相互复制回收不使用的对象)
Java 把内存划分成两种:一种是栈内存,另一种是堆内存。在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java 会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。
堆内存用来存放由 new 创建的对象和数组,在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或者对象之后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或者对象,引用变量就相当于是为数组或者对象起的一个名称。引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用 new
产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉)。