不多说,直接上干货!
其中
1)程序计数器:用于指示当前线程所执行的字节码执行到了第几行,可以理解为当前线程的行号指示器。每个计数器志勇赖记录一个线程的行号,所以它是
线程私有的。
2)虚拟机栈:一个线程的每个方法在执行的同时,会创建一个栈帧,栈帧中存储的有:局部变量、操作栈、动态链接、方法出口等。当方法被调用时,栈帧
在JVM栈中入栈,方法执行完成时栈帧出栈。局部变量表中存储方法的相关局部变量,包括各种基本数据类型,对象引用,返回地址等。每个线程对应着一个虚拟机栈
,因此虚拟机栈也是线程私有的。
3)本地方法栈:本地方法栈的作用,运行机制,异常类型等方面与虚拟机栈相同,唯一不同时虚拟机栈用来执行java方法的,本地方法栈用来执行native方
法的。在许多虚拟机中会将本地方法栈和虚拟机栈放在一起使用。
4)堆区:堆区是java GC机制最重要的区域。堆区是由线程共享的。在虚拟机启动时创建。堆区的存在是为了存储对象实例,原则上所有对象实例都在堆区上分配内存。
5)方法区:方法区是线程共享的,用于存储已经被虚拟机家自爱的类信息、final常量、静态变量、编译器及时编译的代码等。一般不在方法取进行垃圾收集。
寄存器:是给CPU的。
本地方法区:我们暂时设计不到,以后有机会了我们学习,主要运行的时本地系统平台中的内容。它是分版本的,在不同操作系统中不一样的。
如:
两个变量的存储位置不同:
成员变量:存储在堆内存中的对象中,所以也叫对象的特有数据。
静态变量:存储在方法区(共享数据区)的静态区中,所以也叫类的共享数据。
方法区是 jvm加载的时候存字节码用的。
我们在这里主要学习一下栈内存和堆内存,其他的几种以后再学习吧.
栈内存(stack):
存储的都是局部变量,方法中定义的变量都是局部变量。
栈内存处理数据的特点:变量所属作用域一旦结束,该变量就自动释放。
堆内存(heap):
存储的是数组和对象(其实数组就是对象),凡是new建立的,都在堆中,这也就是说我们数组就存放在堆内存中。
再说说堆内存处理数据的特点:
1、每一个实体都有一个首地址值;
2、堆内存中的每一个变量都有默认初始化值,根据类型的不同而不同.整数是0,小数0.0或者0.0f,boolean是false,char是'u0000'
3、垃圾回收机制//自动回收垃圾;
入栈和弹栈有什么区别?
程序计数器:
存放下一条要运行的指令;每个线程都必须用一个独立的程序计数器,用于记录下一条要运行的指令。程序计数器是一块线程私有的内存空间。
JAVA虚拟机栈:
线程私有的内存空间,它保存方法的局部变量,部分返回结果,并参与方法的调用和返回。虚拟机栈在运行的时候使用一种叫做栈帧的数据结构保存上下文数据。在栈帧中,存放了方法的局部变量表、操作数栈、动态连接方法和返回地址等信息。每个方法的调用都伴随着栈帧的入栈操作,每个方法的返回都伴随着栈帧的出栈操作。
本地方法栈:
管理本地方法的调用。和虚拟机一样,它也会抛出StackOverFlowErrow和OutOfMemoryError。
java堆:
几乎所有的对象和数组都是在堆中分配空间的,堆是线程共享的。堆分为新生代和老年代两部分,新生代用于存放刚刚产生的对象和年轻的对象,新生代又可以细分为eden,s0和s1区。eden表示对象的出生地,大部分刚刚出生的对象会存放在这里,s0和s1区空间,称为幸存者,其中存放的对象至少经历了一次垃圾回收,并得以幸存。如果在幸存区的对象到了指定年龄还没有被回收,则有机会进入老年代。
方法区:
被JVM所有线程共享。方法区也称为永久区,主要存放常量和类的定义信息。方法区中最为重要的是类的类型信息,常量池,域信息,方法信息。类的类型信息包括类的完整名称,父类的完整名称,类型修饰符等;常量池包括这个类方法引用的常量信息;域信息包括域名称、域类型和域修饰符;方法信息包括方法名,返回类型、方法参数、方法修饰符。
对永久代的回收,主要从两个方面分析:一是GC对永久区常量池的回收;二是永久区对类元数据的回收。
一是GC对永久区常量池的回收:常量池中的常量没有被任何地方应用,就可以被回收。
二是永久区对类元数据的回收:若系统中动态的生成大量类,可能会导致方法区溢出。JVM要确认一个类信息是否被回收,基本条件有:所有该类的实例被回收,且装载该类的ClassLoader被回收。