问题及答案来源自《Java程序员面试笔试宝典》第四章 Java基础知识 4.8Java平台与内存管理
1、为什么说Java是平台独立性语言?
平台独立性是指可以在一个平台上编写和编译程序,然后在其他平台上运行
保证Java具有平台独立性的机制为中间码和JVM(Java虚拟机),Java程序编译后不是生成了可执行代码,而是
生成了中间码,不同的平台有不同的JVM,由JVM来把中间码翻译成硬件平台能执行的代码(解释执行)
由上述过程可以看出JVM不具有平台独立性,与硬件平台相关
JVM执行中间码(解释执行)的过程分三步进行:
- 代码的装入:由类加载器完成
- 代码的校验:由字节码校验器完成
- 代码的执行:即时编译(完全编译完了执行)和解释执行(边编译边执行)
常见笔试题 - Java程序运行从下到上的环境次序是?
Java程序 =》JVM/JRE =》操作系统 =》硬件
2、Java平台与其他语言平台有哪些区别?
Java平台是一个纯软件的平台,可以运行在一些基于硬件的平台(Linux、Windows等)上
Java平台主要包含两个模块:JVM和Java API
JVM:是一个虚拟出来的计算机,用来把Java编译生成的中间代码转换为机器可以识别的编码并
运行。它有自己完善的硬件架构,例如处理器、堆栈、寄存器等,还具有相应的指令系统,它屏蔽
了具体操作系统的信息,使得Java程序只要生成在JVM上运行的目标代码(字节码)就可以在多种平台
上不加修改地顺利运行
Java API:是Java为了方便开发人员开发而设计的,提供了许多非常有用的接口,这些接口也是用
Java编写的,并且运行在JVM上
3、JVM加载class文件的原理机制是什么?
Java运行指定程序时,JVM会将编译生成的.class文件按照需求和一定的规则加载到内存中,这个加载过程
是由类加载器完成的,具体来说就是由ClassLoader和它的子类来实现的
类的加载的分类:
- 隐式加载:通过new的方式把类加载到JVM中
- 显式加载:通过class.forName()方法来把类加载到JVM中
在Java中,类的加载是动态的,不会一次性把所有类加载到JVM中,而是保证程序运行的基础类(比如基类)
完全加载到JVM中,至于其他类就到需要的时候再加载
类加载的主要步骤:
- 装载:根据查找路径找到class文件,然后导入
- 链接:检查加载的class文件的正确性 =》给类中的静态变量分配存储空间 =》将符号引用转换成直接引用(可选)
- 初始化:对静态变量和静态代码进行初始化工作
4、什么是GC?
在Java中,垃圾回收就是GC,是一个非常重要的概念,主要作用是回收程序中不再使用的内存
在C/C++中需要管理好内存的分配和释放,如果忘记或错误地释放内存往往会导致程序运行不正常甚至程序崩溃,而Java中提供
了垃圾回收器来自动检测对象的作用域,自动的把不再使用的存储空间释放掉。
垃圾回收器的三个任务:
- 分配内存
- 确保被引用对象的内存不被错误地回收
- 回收不再被引用的对象的内存空间
引申 - 是否可以主动通知JVM进行垃圾回收?
开发人员不能直接调用JVM对对象进行垃圾回收,但可以调用System.gc()方法来通知垃圾回收器运行,这个方法的执行会停止
所有响应,去检查内存中是否有可回收的对象,这对程序的正常运行和性能造成极大的威胁,因此在实际编程中不推荐使用
5、Java中是否存在内存泄漏问题?
在Java中判断一个内存空间是否符合垃圾回收的标准有两个:
- 给对象赋值了null,以后再没有使用过
- 给对象赋予了新值,重新分配了内存空间
一般来讲内存泄漏有两种情况:
- 在堆中申请的空间没有被释放
- 对象已不再被使用,但仍然在内存中保留着
垃圾回收机制的引入可以有效的解决前一种情况,但对于后一种情况,垃圾回收机制无法保证不再使用的对象会被释放
因此Java中的内存泄漏指的是上面的第二种情况
在Java中容易引起内存泄漏的原因:
(1)静态集合类,如HashMap和Vector,如果这些容器是静态的,由于它们的生命周期和程序一致,那么容器中的对象
在程序结束之前将不能被释放,从而可能会造成内存泄漏,如下:
1 Vector v = new Vector(10); 2 for(int i=0; i<10; i++){ 3 Object o = new Object(); 4 v.add(o); 5 } 6 7 // 退出循环后o的作用域就结束,但是由于v在使用这些对象,垃圾回收器无法将其回收 8 // 此时就造成了内存泄漏,只有将这些对象从Vector中删除才能释放创建的这些对象
(2)各种连接,例如数据库连接、网络连接以及IO连接等。在对数据库进行操作的过程中,首选需与数据库建立连接,
当不再使用时需调用close方法来释放与数据库的连接,只有连接被关闭后,垃圾回收器才会回收对应的对象,否则
如果使用完后不关闭连接将会造成大量的对象无法被回收,从而引起内存泄漏
(3)监听器,在Java语言中,往往会用到监听器,通常一个应用中会用到多个监听器,但在释放对象的同时往往没有
相应的删除监听器,这也可能导致内存泄漏
(4)变量不合理的作用域,把一个变量定义的作用范围大于其使用范围可能会造成内存泄漏,另外如果没有及时地把
对象设置为null,很有可能会导致内存泄漏
(5)单例模式也可能会造成内存泄漏
6、Java中的堆和栈有什么区别?
共性:都是内存中存放数据的地方
不同之处:
- 栈:存放基本数据类型和引用变量,存取速度快,大小和生存期固定(缺乏灵活性)
- 堆:存放运行时创建的对象(new出来的),存取速度慢,运行时动态分配内存