Java基础知识之——平台与内存管理

来源:互联网 发布:传奇3数据库修改无效 编辑:程序博客网 时间:2024/05/17 04:06

目录:

      一、Java 为什么是平台独立性语言

      二、Java 平台与其他语言平台的区别

      三、JVM 加载 class 文件的原理机制

      四、什么是 GC

      五、Java 是否存在内存泄露

      六、Java 中的堆和栈有什么区别

      七、栈和队列的区别


一、Java 为什么是平台独立性语言


        平台独立性是指可以在一个平台上编写和编译程序,而在其他平台上运行。保证 Java 具有平台独立性的机制为“中间码”和“Java虚拟机(JVM)”。Java 程序被编译后不是生成能在硬件平台上可执行的代码,而是生成了一个“中间码”。不同的硬件平台上会安装有不同的 JVM,由 JVM 来负责把“中间码”翻译成硬件平台能执行的代码,由此可以看出 JVM 不具有平台独立性,而是与硬件平台相关的。


解析执行过程分三步进行:

      1)代码的装入、代码的校验和代码的执行

      2)装入代码的工作由“类装载器完成”

      3)被装入的代码由字节码校验器进行检查


Java 字节码的执行也分为两种方式:即时编译方式和解释执行方式。

      即时编译方式:解释器先将字节码编译成机器码,然后再执行该机器码。

      解析执行方式:解析器通过每次解析并执行一小段代码来完成 Java 字节码程序的所有操作。

而在 C/C++ 语言中,编译后的代码只能在特定的硬件上执行,从而也导致了 C/C++ 没有跨平台的特性,但 C/C++ 的执行效率更高。


二、Java 平台与其他语言平台的区别


        Java 平台是一个纯软件的平台,这个平台可以运行在一写基于硬件的平台上(如Linux、Windows)之上,JVM 是一个虚构出来的计算机,用来把 Java 编译生成的中间代码转换为机器可以识别的编码并运行,它有自己完善得硬件架构,例如处理器、堆栈、寄存器等,还具有相应的指令系统,它屏蔽了与具体系统相关的平台信息,使得 Java 程序只需要生成在 JVM 上运行的目标代码(即字节码),就可以在多种平台上不加修改的顺利运行,每当一个 Java 程序运行时,都会有一个对应的 JVM 实例,只有当程序运行结束后,这个 JVM 才会退出,JVM 实例通过调用类的 main 方法来启动一个 Java 程序


三、JVM 加载 class 文件的原理机制


        Java 语言是一种具有动态性的解析型语言,类(class)只有被加载到 JVM 中后才能运行。当运行指定程序时,JVM 会将编译生成的 .class 文件按照需求和一定的规则加载到内存中,并组织成为一个完整的 Java 应用程序,这个加载过程是由类加载器来完成的,具体来说,就是由 ClassLoader 和它的子类来实现的,类加载器本身也是一个类,其实质是把类文件从硬盘读取到内存中。

        任何一个工程项目都是由许多类组成的,当程序启动时,只把需要的类加载到 JVM 中,其它类只有被使用到的时候才会被加载,采用这种方法,一方面可以加快加载速度,另一方面可以节约程序运行过程中对内存的开销,此外,在 Java 语言中,每个类或接口都对应一个 .class 文件,这些文件可以看成是一个个可以被动态加载的单元,因此当只有部分类被修改时,只需要重新编译变化的类即可,而不需要重新编译所有文件,因此加快了编译速度。


四、什么是 GC


        在 Java 语言中,垃圾回收机制(GC)是一个非常重要的概念,它的主要作用是回收程序中不再使用的内存,在使用 C/C++ 语言进行程序开发时,开发人员必须仔细的管理好内存的分配和释放,如果忘记或者错误的释放内存往往会导致程序运行不正常甚至程序崩溃,为了减轻开发人员的工作,同时增加系统的安全性与稳定性,Java 语言提供了垃圾回收器来自动检测对象的作用域,可自动的把不再被使用的存储空间释放掉,具体而言,垃圾回收器主要负责完成 3 项任务,分配内存、确保被引用对象的内存不被错误的回收及回收不再被引用的对象的内存空间。

        垃圾回收器的存在一方面把开发人员从释放内存的复杂工作中解放出来,提高了开发人员的生产效率,另一方面,对开发人员屏蔽了释放内存的方法,可以避免程序员错误的操作内存而导致应用程序的崩溃,保证了程序的稳定性,但是垃圾回收也带来了问题,为了实现垃圾回收,垃圾回收器必须跟踪内存的使用情况,释放没用的对象,在完成内存的释放后,还需要处理堆中的碎片,这些操作会增加 JVM 的负担,从而降低程序的执行效率。

        对对象而言,如果没有任何变量去引用它,那么该对象将不可能被程序访问,因此可以认为它是垃圾信息,可以被回收,只要有一个以上的变量引用该对象,该对象就不会被垃圾回收。


五、Java 是否存在内存泄露


        内存泄露是指一个不再被程序使用的对象或变量还在内存中占有存储空间,在 C/C++ 语言中,内存的分配与释放是由开发人员来负责的,如果开发人员忘记释放分配的内存空间,就会造成内存泄露,而在 Java 语言中引进垃圾回收机制,由垃圾回收器来负责回收不再使用的对象,既然有垃圾回收器来负责回收垃圾,那么是否还会存在内存泄露的问题呢?


其实在 Java 语言中,判断一个内存空间是否符合垃圾回收的标准有两个:

        第一:给对象赋予了空值 null,以后再没有被使用过

        第二:给对象赋予了新值,重新分配了内存空间


        一般来讲,内存泄露主要有两种情况:一是在堆中申请的空间没有被释放;二是对象已不再被使用,但还仍然在内存中保存着,垃圾回收机制的引用可以有效的解决第一种情况,而对于第二种情况,垃圾回收机制则无法保证不再使用的对象会被释放,因此 Java 中的内存泄露主要是指第二种情况,在 Java 语言中,引起内存泄露的的原因很多,主要有以下几方面的内容:

1)静态集合类:例如 HashMap 和 Vector,如果这些容器为静态的,由于它们的生命周期与程序一致,那么容器中的对象在程序结束之前不能被释放,从而造成内存泄露

2)各种连接:例如数据库连接、网络连接以及 I/O 连接等,在对数据库进行操作的过程中,首先要建立与数据库的连接,当不再使用时需要调用 close 的方法来释放和数据库的连接,只有连接被关闭后,垃圾回收器才会回收相应的对象,否则,在访问数据库的过程中,对 Connection、Statement 以及 ResultSet 不显式的关闭,将会造成大量对象无法被回收,从而引起内存泄露

3)监听器:在 Java 语言中,往往会使用到监听器,通常一个应用中会用到多个监听器,,但在释放对象的同时往往没有删除相应的监听器,这也可能导致内存泄露

4)变量不合理的作用域:一般而言,如果一个变量定义的作范围大于其使用范围,很有可能会造成内存泄露,另一方面如果没有及时的把对象设置为 null 很有可能会导致内存泄露


六、Java 中的堆和栈有什么区别


        在 Java 语言中,堆和栈都是内存中存放数据的地方,变量分为基本数据类型和引用变量,基本数据类型的变量以及对象的应用变量,其内存都分配在栈上,变量出了作用域就会被自动释放,而应用类型的变量,其内存分配在堆上或常量池中,需要通过 new 等方式进行创建。

        具体而言,栈内存主要用来存放基本数据类型与引用变量,栈内存的管理是通过压栈和弹栈操作来完成的,以帧栈为基本单位来管理程序的调用关系,每当有函数调用时,都会通过压栈方式创建新的栈帧,每当函数调用结束后,都会通过弹栈的方式释放栈帧。

        堆内存用来存放运行时创建的对象,一般来讲,通过 new 关键字创建出来的对象都存放在堆内存中,由于 JVM 是基于堆栈的虚拟机,而每个 Java 程序都运行在一个单独的 JVM 实例上,每一个实例唯一对应一个堆,一个 Java 程序内的多个线程也就统一运行在一个单独的 JVM 实例上,因此这些线程之间会共享堆内存,鉴于此,多线程在访问堆中的数据时需要对数据进行同步。


七、栈和队列的区别


栈(Stack):是限定只能在表的一端进行插入和删除操作的线性表。

队列(Queue):是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。


区别:

1)队列先进先出,栈后进先出。

2)对插入和删除的限定:栈是限定只能在表的一段进行插入和删除操作的线性表;队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表,从数据结构的角度看,它们都是线性结构,即数据元素之间的㽑相同,但它们是完全不同的数据类型。除了它们各自基本操作集不同外,主要区别是对插入和删除操作的限定。栈和队列是在程序设计中广泛使用的良好总线性数据结构,它们的特点在于基本操作的特殊性,栈必须按“后进先出”的规则进行操作,而队列必须按“先进先出”的规则进行操作,和线性表相比,它们的插入和删除操作受更多的约束和限定,所以又称为限定性的线性结构表。

3)遍历速度不同,栈只能从头部取数据,也就是说最新放入的最后才能取出来,而在遍历数据的时候还得为数据开辟临时空间,保持数据在遍历前得一致性,队列则不用,它基于地址指针进行遍历,而且可以从头或尾部进行遍历,但不能同时遍历,无需开辟临时空间,因为在遍历的过程中不影响数据结构,速度要快得多。


阅读全文
0 0
原创粉丝点击