Javaguide

值传递 复制了值而已,对主函数中的值 没有改变
地址传递 复制了地址,所以对地址进行操作( *y 就看做指针就好) 改变了主函数中的值
引用传递 传递了地址, 效果和地址传递一样(在 c++ 中才有引用传递,c 语言中没有引用传递)

注意上述三行中的区别,引用传递和地址传递的区别在于 一个复制了地址,一个传递了地址,

反射:让我们在运行时分析类,以及执行类中方法的能力。

用户空间的程序不能直接访问内核空间。

用户进程想要执行 IO 操作的话,必须通过 系统调用 来间接访问内核空间

浮点数没有办法用二进制精确表示,因此存在精度丢失的风险。

不过,Java 提供了BigDecimal 来操作浮点数。BigDecimal 的实现利用到了 BigInteger (用来操作大整数), 所不同的是 BigDecimal加入了小数位的概念。

  1. Java 集合常见知识点&面试题总结(上)
  2. Java 集合常见知识点&面试题总结(下)
  3. Java 容器使用注意事项总结

使用工具类 Arrays.asList() 把数组转换成集合时,不能使用其修改集合相关的方法, 它的 add/remove/clear 方法会抛出 UnsupportedOperationException 异常。所以需要外面再包裹一层new ArrayList(Arrays.asList());

  1. Java 内存区域

线程私有的:

  • 程序计数器
  • 虚拟机栈
  • 本地方法栈

线程共享的:

  • 方法区
  • 直接内存 (非运行时数据区的一部分)

对象的创建

Java 对象的创建过程我建议最好是能默写出来,并且要掌握每一步在做什么。

Step1:类加载检查

虚拟机遇到一条 new 指令时,首先将去检查这个指令的参数是否能在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否已被加载过、解析和初始化过。如果没有,那必须先执行相应的类加载过程。

Step2:分配内存

类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需的内存大小在类加载完成后便可确定,为对象分配空间的任务等同于把一块确定大小的内存从 Java 堆中划分出来。分配方式“指针碰撞”“空闲列表” 两种,选择哪种分配方式由 Java 堆是否规整决定,而 Java 堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定

内存分配的两种方式 (补充内容,需要掌握):

  • 指针碰撞 :
    • 适用场合 :堆内存规整(即没有内存碎片)的情况下。
    • 原理 :用过的内存全部整合到一边,没有用过的内存放在另一边,中间有一个分界指针,只需要向着没用过的内存方向将该指针移动对象内存大小位置即可。
    • 使用该分配方式的 GC 收集器:Serial, ParNew
  • 空闲列表 :
    • 适用场合 : 堆内存不规整的情况下。
    • 原理 :虚拟机会维护一个列表,该列表中会记录哪些内存块是可用的,在分配的时候,找一块儿足够大的内存块儿来划分给对象实例,最后更新列表记录。
    • 使用该分配方式的 GC 收集器:CMS

选择以上两种方式中的哪一种,取决于 Java 堆内存是否规整。而 Java 堆内存是否规整,取决于 GC 收集器的算法是”标记-清除”,还是”标记-整理”(也称作”标记-压缩”),值得注意的是,复制算法内存也是规整的。

内存分配并发问题(补充内容,需要掌握)

在创建对象的时候有一个很重要的问题,就是线程安全,因为在实际开发过程中,创建对象是很频繁的事情,作为虚拟机来说,必须要保证线程是安全的,通常来讲,虚拟机采用两种方式来保证线程安全:

  • CAS+失败重试: CAS 是乐观锁的一种实现方式。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。虚拟机采用 CAS 配上失败重试的方式保证更新操作的原子性。
  • TLAB: 为每一个线程预先在 Eden 区分配一块儿内存,JVM 在给线程中的对象分配内存时,首先在 TLAB 分配,当对象大于 TLAB 中的剩余内存或 TLAB 的内存已用尽时,再采用上述的 CAS 进行内存分配

Step3:初始化零值

内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头),这一步操作保证了对象的实例字段在 Java 代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。

Step4:设置对象头

初始化零值完成之后,虚拟机要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的 GC 分代年龄等信息。 这些信息存放在对象头中。 另外,根据虚拟机当前运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。

Step5:执行 init 方法

在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但从 Java 程序的视角来看,对象创建才刚开始,<init> 方法还没有执行,所有的字段都还为零。所以一般来说,执行 new 指令之后会接着执行 <init> 方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算完全产生出来。

对象的内存布局

在 Hotspot 虚拟机中,对象在内存中的布局可以分为 3 块区域:对象头实例数据对齐填充

Hotspot 虚拟机的对象头包括两部分信息第一部分用于存储对象自身的运行时数据(哈希码、GC 分代年龄、锁状态标志等等),另一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。

  1. JVM 垃圾回收
IMG_2072.jpg
  1. JDK 监控和故障处理工具

postman用来测试服务。

jmeter用来做性能测试。

jconsole 堆内存的监控、CPU占用率等等。

jvisualvm一样,可以下载插件,查看GC。

流程

查看进程的问题

jps:查看当前系统的java进程,得到pid。 Jps, ups -l

jmap:查看对内存占用情况 jmap -heap 进程id

jconsole:堆内存的监控、CPU占用率等等。

jvisualvm:一样,可以下载插件,查看GC。

jstack 进程id,找到有问题的线程,可以定位到源码行(),也可以看到是否有锁

查看线程

top命令查看哪个进程对CPU的占用过高 (jps:查看当前系统的java进程,得到pid。 Jps, ups -l)

ps H -eo pid,tid,&cpu | grep 进程id

jstack 进程id,找到有问题的线程,可以定位到源码行(),也可以看到是否有死锁

查看对象运行时的内存结构等(HSDB工具)

jps得到进程id

首先进入jdk安装目录,进去后输入进程id

1
java -cp ./lib/sa-jdi.jar sun.jvm.hotspot.HSDB

查找某个对象

1
select d from cn.itcast.jvm.t3.bytecode.Dog d

根据上面的到的地址查找到对象,然后对象头又16个字节,前8个字节是MarkWorld,后八个字节就是对象的Class指针。

IMG_2073.jpg

Java类加载机制的几个个阶段,加载、验证、准备、解析、初始化【jvm】

IMG_2074.jpg

  • instanceKlass保存在方法区。JDK 8以后,方法区位于元空间中,而元空间又位于本地内存中
  • java_mirror则是保存在堆内存中
  • InstanceKlass和*.class(JAVA镜像类)互相保存了对方的地址*
  • _类的对象在对象头中保存了.class的地址(也可以说是_java_mirror的地址)。让对象可以通过其,找到方法区(元空间)中的instanceKlass,从而获取类的各种信息。

加载

链接

  • 验证
  • 准备
  • 解析

初始化

还不明白Java从编译到执行的过程?看这一篇

编译 -> 加载 -> 解释 -> 执行

javac,编译,将源码文件(.java)编译成JVM可以解释的class文件

字节码存储在硬盘上,需要运行时,由类加载系统负责将累的信息加载到内存中(方法区),使用类加载器进行加载

解释就是 直接解释(JVM对字节码逐条解释的) + 即时编译器解释(对某段热点代码进行整体遍后执行,编译需要一定的时间,但是编译后运行时间很快)

执行

a++是在槽位上+的,所以与++a的区别是闲iload还是闲iinc的区别

而静态变量的自增需要放到操作数栈中。

原子性、可见性(太多次,直接从主存缓存到工作内存中去了)、有序性(JIT的优化)。

new singleinstance()的时候的时候,init和putstatic是顺序不固定的,所以单例模式中也要用volitile保证有序性。

红黑树

红黑树的应用 :TreeMap、TreeSet以及JDK1.8的HashMap底层都用到了红黑树。

为什么要用红黑树? 简单来说红黑树就是为了解决二叉查找树的缺陷,因为二叉查找树在某些情况下会退化成一个线性结构。详细了解可以查看 漫画:什么是红黑树?(也介绍到了二叉查找树,非常推荐)

红黑树的基本性质与操作

Java基础

对于异常重写方法不能抛出新的异常或者比被重写方法声明的检查异常更广的检查异常。但是可以抛出更少,更有限或者不抛出异常

WulzDmXEq1HxKCk

所以应该选abc,不能选d。

Author: Jcwang

Permalink: http://example.com/2022/07/18/javaguide/