1. Java跨平台原理

简单描述java 的运行机制 简述java的运行机制?_Java


Java实现跨平台是JVM(Java虚拟机)起的作用,如果是C/C++的编译方式,一旦换了一个平台,那么就需要重新编译一份对应的可执行代码,但是Java则不同,编译好了一份Java字节码,换到不同的平台上时,并不需要重新编译,前提是这些平台上都安装了相应平台的JVM,JVM不是跨平台的。

2. 垃圾回收器的基本原理
垃圾回收器通常是作为一个单独的低级别的线程运行,在不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有的对象进行垃圾回收。
垃圾回收器不可以马上回收内存,程序员可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。

3. 垃圾回收机制
(1)分代复制垃圾回收
不同的对象的生命周期是不一样的,因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率。在Java程序运行的过程中,会产生大量的对象,其中有些对象是与业务信息相关,比如Http请求中的Session对象、线程、Socket连接,这类对象跟业务直接挂钩,因此生命周期比较长,但是还有一些对象,主要是程序运行过程中生成的临时变量,这些对象生命周期会比较短,如:String对象,由于其不变类的特性,系统会产生大量的这些对象,有些对象甚至只使用一次即可回收,如果每次垃圾回收都是对整个堆空间进行回收,花费时间会相对较长,并且生命周期长的对象依旧存在,因此引入分代回收,把不同生命周期的对象放在不同代上,不同代上采用最适合它的垃圾回收方式进行回收
虚拟机中的对象共划分为三个代:年轻代(Young Generation)、老年代(Old Generation)和持久代(Permanent Generation)。由于对象进行了分代处理,因此垃圾回收区域、时间也不一样。
(2)标记垃圾回收
在使用标记清除算法时,未引用对象并不会被立即回收,取而代之的做法是:垃圾对象将一直累积到内存耗尽为止,当内存耗尽时,程序将会被挂起,垃圾回收开始执行,当所有的未引用对象被清理完毕时,程序才会继续执行,标记清除算法由两个阶段组成:
标记阶段:标记所有的可访问对象
收集阶段:垃圾收集算法扫描堆,并回收所有的未标记对象
(3)增量垃圾回收
简单地说,它的存在是为了解决标记清除的长停顿问题,增量收集器把堆栈分为多个域,每次仅从一个域收集垃圾,这会造成较小的应用程序中断。

4. JVM加载class文件的原理
JVM加载class对象是懒加载,按需加载:
(1)查找当前ClassLoader(类装载器,就是寻找类或接口字节码文件进行解析并构造JVM内部对象表示的组件)中是否有此class的类对象,有则返回
(2)若没有的话,向上递归所有的父ClassLoader中有无此class类对象,有则返回
(3)若还没有,查找BootstrapClassLoader中有无此class类对象,有则返回
(4)若还没有的话,使用findClass或resolveClass加载类对象
a.读取class二进制文件
b.根据字节数组成Class对象
c.缓存到当前ClassLoader中

5. Java内存

堆(heap)与栈(stack)

在Java中,Main函数就是栈的起始点,也是程序的起始点。程序要运行总是有一个起点的(程序执行的入口)。

简单描述java 的运行机制 简述java的运行机制?_垃圾回收_02


概括:
(1)栈是运行时的单位,而堆是存储的单元。
(2)栈解决程序的运行问题,即程序如何执行,或者说如何处理数据,堆解决的是数据存储的问题,即数据怎么放,放在哪。

在Java中一个线程就会有一个线程栈与之对应,这点很容易理解,因为不同的线程执行逻辑有所不同,因此需要一个独立的线程栈。

而堆则是所有线程共享的。

疑问一:为什么要把堆和栈区分出来呢?栈中不是也可以存储数据吗?

(1)从软件设计的角度看,栈代表了处理逻辑,而堆代表了数据,这样分开,使得处理逻辑更为清晰。分而治之的思想。这种隔离、模块化的思想在软件设计的方方面面都有体现。

(2)堆与栈的分离,使得堆中的内容可以被多个栈共享(也可以理解为多个线程同时访问同一个对象)。好处如下:

a.提供了一种有效的数据交互方式(如:共享内存)

b:堆中的共享常量和缓存可以被所有栈访问,节省了空间。

(3)栈因为运行时的需要,比如保存系统运行时的上下文,需要进行地址段的划分。由于栈只能向上增长,因此就会限制住栈存储内容的能力,而堆不同,堆中的对象是可以根据需要动态增长的,所以栈和堆的拆分使得动态增长成为可能,相应栈中只需要记录堆中的一个地址即可。

(4)面向对象就是堆和栈的完美结合。其实面向对象方式的程序与以前结构化的程序在执行上并没有任何区别,但是面向对象的引入,使得对待问题的思考方式发生了改变,而更接近于自然方式的思考。当我们把对象拆开会发现,对象的属性其实就是数据,存放在堆中;而对象的行为(方法)就是运行逻辑,放在栈中。我们在编写对象的时候,其实就是编写了数据结构,也编写了处理数据的逻辑。

疑问二:堆中存什么?栈中存什么?
(1)栈存储的信息都是跟当前线程(或程序)相关的信息。(局部变量、程序运行状态、方法、返回值)等。栈中存的是基本数据类型和堆中对象的引用,一个对象的大小是不可估计的,或者说是可以动态变化的,但是在栈中,一个对象只对应了一个4Byte的引用(堆栈分离的好处)。
(2)堆只负责存储对象信息。

疑问三:为什么不把基本类型放堆中呢?
(1)其占用的空间一般是1-8个字节,需要空间比较少
(2)而且因为是基本类型,所以不会出现动态增长的情况——长度固定,因此栈中存储就够了。如果把它放在堆中是没什么意义的(还会浪费空间)

疑问四:Java中的参数传递是传值还是传引用?
(1)对象类型传递是引用值传递,基本数据类型传递是值传递。实际上这个传入函数的值是对象引用的拷贝,即传递的是引用的地址值所以还是按值传递。
(2)堆和栈中,栈是程序运行最根本的东西,程序运行可以没有堆,但是不能没有栈。而堆是为栈进行数据存储服务的,可以说堆就是一块共享的内存。不过正是因为堆和栈的分离的思想才使得Java的垃圾回收成为可能。
(3)Java中,栈的大小通过-Xss来设置,当栈中存储的数据比较多时,需要适当调大这个值,否则会出现java.lang.StackOverflowError异常。