一、JVM基础知识
Java体系结构:Java程序设计语言、Java class文件格式、Java虚拟机、Java应用编程接口(API)。这四者的关系:把Java写的源代码编译成Java class文件,然后在Java虚拟
机中运行,编写程序时通过调用实现了Java API的类的方法来访问系统资源。Java虚拟机和Java API共同组成一个“平台”。
JVM主要任务是装载class文件并执行其中的字节码,JVM通过类加载器来从程序和Java API中装载class文件,Java API中只有在程序执行时需要的那些类才会被装载。
Java有两种方法:Java方法和本地方法。前者由Java语言编写,编译成字节码,存储在class文件中;后者由其他语言(如C++、C)编写,编译成和处理器相关的机器码,保存在
动态链接库中,格式是各个平台专有的。运行中的Java程序调用本地方法时,JVM装载包含这个本地方法的动态库,并调用这个方法。本地方法是联系Java程序和底层主机操作系
统的连接方法。
JVM:Java Virtual Machine(Java虚拟机),负责执行符合规范的Class文件;
JRE: Java Runtime Environment (java运行环境),包含JVM和类库;
JDK: Java Development Kit(java开发工具包),包含JRE和开发工具包;
returnAddress类型会被Java虚拟机的jsr、ret和jsr_w指令所使用。returnAddress类型的值指向一条虚拟机指令的操作码。与前面介绍的那些数值类的原始类型不同,
returnAddress类型在Java语言之中并不存在相应的类型,也无法在程序运行期间更改returnAddress类型的值。
Java虚拟机不提供操作boolean类型的字节码指令,程序在编译后boolean类型都转化成了int操作。但是Java虚拟机支持boolean类型的数组的访问和修改,共用byte类型数组
的字节码指令。
Java虚拟机中,数据类型可以分为两类:基本类型和引用类型。基本类型的变量保存原始值,即:他代表的值就是数值本身;而引用类型的变量保存引用值。“引用值”代表了某个对象的引用,而不是对象本身,对象本身存放在这个引用值所表示的地址的位置。
基本类型包括:byte,short,int,long,char,float,double,Boolean,returnAddress
引用类型包括:类类型,接口类型和数组。
二、栈和堆
栈和堆是做什么的?
栈解决程序运行问题,即程序如何执行,或如何处理数据;堆解决数据存储问题,即数据怎么放、放哪。堆和栈中,栈是程序运行最根本的东西。程序运行可以没有堆,但是不能没有栈。而堆是为栈进行数据存储服务,说白了堆就是一块共享的内存。不过,正是因为堆和栈的分离的思想,才使得Java的垃圾回收成为可能。Main函数是栈的起点,也是程序的起点。
为什么要把栈和堆区分开?
1.栈代表了处理逻辑,堆代表了数据;2.这种处理方式使得堆中的内容可以被多个栈共享,(或者多个线程访问一个对象),是一种有效的数据交互方式,同时节省了空间;3. 栈因为运行时的需要,比如保存系统运行的上下文,需要进行地址段的划分。由于栈只能向上增长,因此就会限制住栈存储内容的能力。而堆不同,堆中的对象是可以根据需要动态增长的,因此栈和堆的拆分,使得动态增长成为可能,相应栈中只需记录堆中的一个地址即可;4. 面向对象是堆栈的完美结合,对象的属性就是数据,存放在堆中,对象的方法就是运行逻辑,存放在栈中。
栈和堆中分别存放什么?Java的传值和传引用分别指什么?
堆中存的是对象。栈中存的是基本数据类型和堆中对象的引用。一个对象的大小是不可估计的,或者说是可以动态变化的,但是在栈中,一个对象只对应了一个4btye的引用(堆栈分离的好处))。为什么不把基本类型放堆中呢?因为其占用的空间一般是1~8个字节——需要空间比较少,而且因为是基本类型,所以不会出现动态增长的情况——长度固定,因此栈中存储就够了,如果把他存在堆中是没有什么意义的,还会浪费空间。程序运行永远都是在栈中进行的,因而参数传递时,只存在传递基本类型和对象引用的问题。不会直接传对象本身。在运行栈中,基本类型和引用的处理是一样的,都是传值,所以,如果是传引用的方法调用,也同时可以理解为“传引用值”的传值调用,即引用的处理跟基本类型是完全一样的。但是当进入被调用方法时,被传递的这个引用的值,被程序解释(或者查找)到堆中的对象,这个时候才对应到真正的对象。如果此时进行修改,修改的是引用对应的对象,而不是引用本身,即:修改的是堆中的数据。所以这个修改是可以保持的了。
对象,从某种意义上说,是由基本类型组成的。可以把一个对象看作为一棵树,对象的属性如果还是对象,则还是一颗树(即非叶子节点),基本类型则为树的叶子节点。程序参数传递时,被传递的值本身都是不能进行修改的,但是,如果这个值是一个非叶子节点(即一个对象引用),则可以修改这个节点下面的所有内容。
Java对象的大小?
一个空Object对象的大小是8byte,这是大小是保存堆中一个没有任何属性的对象的大小。
Object obj = new Object();
这里它占用了12byte,其中4byte是栈中保存引用所需要的空间,8byte是堆中对象的大小。因为Java中的非基本类型的对象都需要继承Object,因此无论什么Object对象其大小都大于8byte。
Class NewObject {
int count;
boolean flag;
Object ob;
}
其大小为:空对象(8byte)+ Int大小(4byte)+ Boolean大小(1byte)+ 对象引用大小(4byte)= 17byte;但是Java对对象内存分配都是8的整数倍,因此实际存储大小为24byte。同理,我们可以知道基本类型的包装类型的大小至少为16byte。
Java的引用类型有哪些?
对象引用分为强引用、软引用、弱引用和虚引用。
强引用:一般声明对象是虚拟机生成的引用,强引用环境下,垃圾回收需要严格判断当前对象是否被强引用,如果被强引用,就不会被垃圾回收;
软引用:软引用一般被当做缓存来使用,与强引用的区别是,在垃圾回收时,JVM会根据当前系统的剩余内存来决定是否对软引用进行回收。如果剩余内存比较紧张,则JVM会回收软引用所引用的空间;反之,如果内存相对比较富余,则不会回收。也就是当JVM发生OutOfMemory时,肯定没有软引用的存在;
弱引用:也是被当做缓存来使用,但是,它在垃圾回收时是一定会被回收的,因此其生命周期只存在于一个垃圾回收周期内。