一、Java介绍
- Java的一些特性
- Java是纯面向对象语言,所有代码必须定义在类中,不容许单独的过程与函数存在,方法必须隶属于类或对象。
- 成员通过类名(静态方法)或对象(实例方法)调用。
- 非静态方法属于实例成员(对象),而静态方法才属于类成员。
- 类的成员= 类里面定义的所有东西(包括静态和非静态的字段、方法、嵌套类等)
- 实例成员= 必须通过对象.xxxoff-heap访问的非静态部分(属于具体对象)
- Java的组成
- JDK:Java Delelopment Kit Java开发工具包
- JRE:Java Runtime Environment Java运行时环境
- JVM: Java Vertual Machine Java虚拟机
二、JVM虚拟机
- Java的跨平台开发:
- JVM中的内存结构
- 直接内存:直接向操作系统申请内存,不受 JVM 堆内存大小限制。
- 方法区(Method Area)/元空间(Metaspace):是 JVM 中用来存储类的结构信息、常量、静态变量、JIT 编译代码等的内存区域。
- 运行时常量池(JVM常量池):属于方法区的一部分,存放编译期生成的各种字面量和符号引用。可以动态添加常量(如 String.intern())。
- Java 堆(Heap):是垃圾收集器管理的主要区域,因此也被称作GC 堆(Garbage Collected Heap)。是 JVM 中最大的一块内存区域,存储着所有通过 new 关键字创建的对象实例和数组,以及这些对象的实例变量(字段)等。是垃圾回收器(GC)主要管理的区域。如果没有内存可用且 GC 无法回收,会抛出 OutOfMemoryError。
- 程序计数器:当前线程所执行字节码的行号指示器。
- 本地方法栈:执行 native 本地方法,运行 C/C++ 等 native 代码,如 JNI
- 虚拟机栈(JVM Stack):栈区是 JVM 为每个线程分配的运行内存区域,存储每个方法调用时的栈帧,栈帧是栈区的最小单位。
- 栈帧:方法调用时在栈区里开辟的一小块内存单元,存储方法执行过程中所需要的信息(局部变量-存储了基本数据类型的值、对象的引用变量、操作数、中间结果和方法出口等)。
- 压栈出栈:方法调用 → 入栈;方法结束 → 出栈。
- 异常情况:StackOverflowError:栈深度过大。OutOfMemoryError:无法申请足够内存创建新的栈。
3、池Pool
层次 | 池的名称 | 位置 | 说明 |
外存层面 | Class 文件常量池(Constant Pool Table) | 存储在磁盘上的 .class 文件内部 | 属于 Class 文件格式规范,同时为JVM 加载和执行类文件提供必要的符号信息支持。 |
JVM内存层面 | 运行时常量池 | 方法区(元空间) | 运行时常量池是Class 文件常量池被JVM加载在内存中的映射 |
字符串常量池 | 堆(JDK1.7+) | 字面量字符串共享 | |
包装类对象缓存池 | 堆 | Integer、Byte、Boolean 缓存 | |
标准库层面 | 线程池(ThreadPoolExecutor) | 堆 | 复用线程资源 |
对象池(Object Pool) | 堆 | Apache Commons Pool 等 | |
NIO ByteBuffer 池 | 堆/堆外 | 复用缓冲区(Netty) | |
应用层面 | 数据库连接池 | 堆 | DBCP、HikariCP、Druid 等 |
缓存池(对象缓存) | 堆 | 业务自定义缓存池 |
4、JVM 的垃圾回收机制(GC garbage collection)
- -Xms1G → 初始堆大小 =1GB
- -Xmx2G → 最大堆大小 =2GB
- -Xmn500M → 新生代大小 =500MB
- -XX:MaxPermSize=64M → 永久代最大值 =64MB(仅适用于 JDK 8 之前)
- -XX:SurvivorRatio=N → Eden : Survivor = N : 1 : 1(即 Eden 占新生代的 3/5,两个 Survivor 区各占 1/5)
垃圾回收算法:
- 1. 效率不行,标记和清除的效率都不高
- 2. 标记和清除后会产生大量的不连续的空间分片,可能会导致之后程序运行的时候需分配大对象而找不到连续分片而不得不触发一次GC;
三、Kotlin介绍
- Java 程序编译成字节码(.class 文件),运行在JVM(Java Virtual Machine)上。
- Kotlin 也是编译成字节码,运行在同一个 JVM 上。
- 所以 Kotlin 和 Java 的 .class 文件可以在同一个项目中无缝混用。
- Kotlin 可以直接调用 Java 的类、方法、库,没有任何额外转换。
- Java 也能调用 Kotlin 写的代码(虽然 Kotlin 的一些特性在 Java 调用时可能不那么优雅)。
- Kotlin 中声明变量不必指定变量的类型,Kotlin 会隐式指定类型。
- Kotlin 中声明变量,可以使用 var 或 val 关键字
- Kotlin 中,val 变量赋值后,无法更改使用 val 关键字声明的变量
- Kotlin 中的 println() 函数调用了 System.out.println() 函数
- 更简洁(减少 Java 的模板代码)
- 更安全(尤其是空指针安全)
- 更现代(支持协程、扩展函数、数据类等特性)