博客
关于我
面试题二十:Java高级面试 —GC相关
阅读量:589 次
发布时间:2019-03-11

本文共 2317 字,大约阅读时间需要 7 分钟。

一、类加载器

1. 什么是类加载器

类加载器(ClassLoader)是Java运行时环境中用于动态加载类文件到内存中的关键组件。它的主要职责是根据类路径(classpath)的配置,自动查找并加载所需的类文件。当应用程序运行时,类加载器会根据需要动态加载类文件,确保程序能够在运行时加载新类或修复已有类。

2. 类加载器的类型

从程序员的角度来看,常见的类加载器类型包括:

  • BootStrap ClassLoader:这是最底层的类加载器,负责加载Java平台的核心类库。它通常不会根据用户需求进行修改,专门用于加载Java Runtime Environment(JRE)中的核心系统类。

  • Extension ClassLoader:负责加载应用程序所依赖的扩展类库。这些类库通常位于JRE的ext目录下,类加载器会自动查找并加载这些扩展类。

  • App ClassLoader:用户应用程序常用的类加载器,它负责加载应用程序的主类和相关依赖类。开发者可以通过配置classpath来指定加载哪些类。

从Java虚拟机(JVM)的角度来看,所有的类加载器都可以分为两大类:

  • 启动类加载器:即上述的BootStrap ClassLoader,它负责加载JVM自身以及核心系统类。

  • 其他类加载器:由用户应用程序定义的类加载器,负责加载应用程序的主类和相关依赖类。

3. 双亲委托模型

在Java的类加载机制中,双亲委托模型是核心的加载机制。这个机制确保了类加载的安全性和一致性。具体来说,当一个类加载器尝试加载一个类时,它会首先委托给其父类加载器(即双亲)进行加载。如果父类加载器无法找到该类,子类加载器会自己尝试从类路径中查找。

双亲委托模型的核心逻辑可以用以下代码表示:

public class MyClassLoader extends ClassLoader {
public Class
loadClass(String className) throws IOException {
return super.loadClass(className);
}
}

需要注意的是,默认的双亲委托模型会自动为所有自定义的ClassLoader添加双亲委托关系。如果需要自定义双亲委托行为,可以通过setDelegation()方法进行配置。

4. 类加载过程

类加载过程可以分为以下几个阶段:

  • 验证(Verification):确保类文件的格式和语法正确无误。

  • 准备(Preparation):将类文件转化为方法码( bytecode),并为类和其成员(字段、方法)分配内存空间。

  • 解析(Resolution):将符号引用转化为直接引用。这个过程包括类常量的计算和动态链接。

  • 初始化(Initialization):执行类构造器(Class Constructor)进行类变量和方法的初始化。

  • 理解这些阶段的逻辑有助于我们更好地理解类加载器的工作原理,以及如何优化应用程序的类加载性能。


    二、Java堆、栈

    1. Java程序运行时的内存分配策略

    在Java中,内存分配策略直接关系到程序的性能。堆内存是Java最大的动态内存区域,主要用于存储对象实例。而栈内存则用于存储程序执行过程中方法调用的上下文。

    内存分配策略可以分为以下几种:

    • 最佳-fit allocation(最佳匹配分配):尽可能找到最小的可用内存块来分配当前请求的内存。

    • worst-fit allocation(最坏匹配分配):优先分配最大的可用内存块给当前请求。

    • best-fit allocation within worst-fit allocation(最坏匹配下的最佳匹配分配):优先分配最小的可用内存块,但在整个分配过程中仍然遵循最坏匹配策略。

    选择哪种内存分配策略会直接影响内存碎片的产生和内存利用率。

    2. 栈内存、堆内存的区别

    栈内存和堆内存是Java内存管理中的两个核心概念。两者在内存作用和管理策略上有明显差异。

    • 栈内存

      • 存取速度快,因为它位于CPU缓存区。
      • 内存生命周期短,通常与方法调用或函数执行相关联。
    • 堆内存

      • 存取速度较慢,因为它位于磁盘或其他慢速存储介质上。
      • 内存生命周期长,主要用于存储对象实例。

    这两种内存区域的划分直接关系到Java程序的性能表现。

    3. Java内存回收机制

    Java采用垃圾回收(Garbage Collection,GC)机制来管理内存。垃圾回收机制通过标记无用对象并进行回收,确保内存能够高效利用。

    常见的垃圾回收算法包括:

    • 标记-清除算法:通过标记无用对象并清除它们的内存。

    • 复制算法:将内存分为两块,交替使用,定期对一块进行回收。

    • 标记-整理算法:标记无用对象后,通过移动指针将空闲内存连结起来,减少内存碎片。

    垃圾回收机制的效率直接影响到Java程序的性能表现。

    4. Java内存泄漏引起的原因

    内存泄漏是Java程序中常见的性能问题之一。内存泄漏的主要原因包括:

    • 引用强引用:如果某个对象被强引用(Reference),它将永远不会被垃圾回收器回收。

    • 资源未正确释放:数据库连接、文件流等资源未在使用完成后被正确关闭。

    • 循环依赖:对象间形成环状引用,导致垃圾回收器无法识别这些对象为无用对象。

    在开发Java程序时,需要注意对对象生命周期的管理,避免因循环依赖等原因导致内存泄漏。


    总结

    堆和栈是Java内存管理的两大核心概念。堆主要用于存储对象实例,而栈用于存取方法调用上下文。理解它们的区别和内存管理策略,有助于优化Java程序的性能表现。

    转载地址:http://rfttz.baihongyu.com/

    你可能感兴趣的文章
    Mysql 自定义函数
    查看>>
    mysql 行转列 列转行
    查看>>
    Mysql 表分区
    查看>>
    mysql 表的操作
    查看>>
    mysql 视图,视图更新删除
    查看>>
    MySQL 触发器
    查看>>
    mysql 让所有IP访问数据库
    查看>>
    mysql 记录的增删改查
    查看>>
    MySQL 设置数据库的隔离级别
    查看>>
    MySQL 证明为什么用limit时,offset很大会影响性能
    查看>>
    Mysql 语句操作索引SQL语句
    查看>>
    MySQL 误操作后数据恢复(update,delete忘加where条件)
    查看>>
    MySQL 调优/优化的 101 个建议!
    查看>>
    mysql 转义字符用法_MySql 转义字符的使用说明
    查看>>
    mysql 输入密码秒退
    查看>>
    mysql 递归查找父节点_MySQL递归查询树状表的子节点、父节点具体实现
    查看>>
    mysql 通过查看mysql 配置参数、状态来优化你的mysql
    查看>>
    mysql 里对root及普通用户赋权及更改密码的一些命令
    查看>>
    Mysql 重置自增列的开始序号
    查看>>
    mysql 锁机制 mvcc_Mysql性能优化-事务、锁和MVCC
    查看>>