JAVA文档
https://docs.oracle.com/javase/tutorial/essential/index.html
内存信息dump
# 导出整个JVM 中内存信息
jmap -dump:format=b,file=文件名 [pid]
# 查看JVM堆中对象详细占用情况
jmap -histo [pid]
# dump内容分析,默认端口 7000
jhat -J-Xmx1024M [file]
查看JVM默认启动参数
java -XX:+PrintFlagsFinal -version
设置方法区(永久代)大小
-XX:PermSize=10M -XX:MaxPermSize=10M
在JDK1.8之后使用 -XX:MaxMetaspaceSize=128m 设置元空间大小(JVM参数PermSize 和 MaxPermSize会被忽略,当前在启动时会有警告信息)
设置GC日志输出
-XX:+PrintGC 简略信息输出
-XX:+PrintGCDetails 详细信息输出
-XX:+PrintGCTimeStamps gc时间打印
-XX:+PrintGCApplicationStoppedTime 停顿时间
-XX:+PrintGCApplicationConcurrentTime 打印每次垃圾回收前,程序未中断的执行时间
-XX:+PrintHeapAtGC 打印GC前后的详细堆栈信息
-Xloggc:filename 把相关日志信息记录到文件以便分析.
-XX:+PrintClassHistogram 垃圾回收前打印类信息柱状图
-XX:+PrintTenuringDistribution 查看每次minor GC后新的存活周期的阈值
-XX:+PrintTLAB 查看TLAB空间的使用情况
GC日志样例:
2019-04-03T17:25:10.175+0800: 4.311: [GC (Allocation Failure) 895844K->20823K(1363968K), 0.0159384 secs] 2019-04-03T17:25:10.415+0800: 4.551: [GC (Metadata GC Threshold) 394193K->22130K(1810944K), 0.0099884 secs] 2019-04-03T17:25:10.425+0800: 4.561: [Full GC (Metadata GC Threshold) 22130K->15705K(1925632K), 0.0482205 secs]
Metadata GC Threshold 代表 Metaspace 不够了,MetaspaceSize默认只有21M左右。
metaspace说明:传送门,简单来说就是用 Metaspace 代替了永久区。
查看当前jvm实例使用的垃圾收集器
jmap -heap pid
输出结果中,using thread-local object allocation. 下面一行就是当前使用的垃圾收集器
JDK8 默认堆大小
初始化 128M,最大2G,且默认使用 Parallel 垃圾收集器(标记整理),初始化栈大小为1M。
uintx InitialHeapSize := 134217728 uintx MaxHeapSize := 2147483648 bool UseParallelGC := true bool UseParallelOldGC = true bool UseAdaptiveSizePolicy = true intx ThreadStackSize = 1024 bool UseConcMarkSweepGC = false uintx MetaspaceSize = 21807104
且默认打开了 UseAdaptiveSizePolicy 配置,用于动态调整Eden和Survivor比例,进入老年代对象年龄等。
使用 jcmd pid VM.flags 查看当前java进程的启动参数(或者指定查看参数:jinfo -flag ThreadStackSize pid)
使用 -Xss2M 指定 线程栈大小。
sunhotspot jvm和ibmjvm中都把引用实现为一个指针,因此在64位平台上,占8个字节,在32位平台上占4个字节。
-XX:+UseCompressedOops 默认为true,开启指针压缩,这样 java引用就只占4个字节,若为开启则在64位机器上引用会占8个字节。
JDK8元空间说明:
http://caoyaojun1988-163-com.iteye.com/blog/1969853
http://www.infoq.com/cn/articles/Java-PERMGEN-Removed
http://www.cnblogs.com/redcreen/archive/2011/05/04/2037057.html
G1垃圾收集器GC日志说明
https://blogs.oracle.com/poonam/understanding-g1-gc-logs
arraylist get(负数) 抛出 IndexOutOfBoundsException 没有栈异常信息
long 转 int 可能为负数
3421665166L 强转为 int 输出为 -873302130
fullGC 过多 导致 用户线程暂停,zk心跳异常
日志打了一半,后续既没有info日志,也没有异常日志
jar 包 release 版本以前可以覆盖,导致本地仓库的jar包是老版本,使用rources 包是最新的,查看包的源码是没有问题的,
但是运行一段时间后,执行到调用该方法的地方,则报错,无此方法。
JSON 相关框架性能比较
整体来说,小对象的序列化和反序列化 ,gson表现最好,大对象的序列化和反序列化, jackson 是更好的选择,fastjson 虽然也在速度上也不错,但其功能完备性相对较差
http://www.cnblogs.com/java-class/p/6653735.html http://www.bijishequ.com/detail/373398
fastjson 普及性的问题:
https://www.zhihu.com/question/44199956
spring事务方法内部调用生效
使用 AopContext.currentProxy() 直接获取代理对象,执行方法调用
并在配置中指定
<property name="exposeProxy">
<value>true</value>
</property
多个事务管理器,默认使用的事务管理器
多个事务管理器,默认使用的事务管理器,根据加载顺序决定,第一个加载到的事务管理器,作为默认事务管理器
@ComponentScan 注解 默认包扫描
如果 basePackages 未配置,则默认从使用这个注解的类所在的包开始扫描
下面的调用,在找不到 NotSupportedException (此类由运行时加载,运行环境中可能找不到) 时会抛出异常:
public final class Test {
private Test() throws NotSupportedException {
throw new NotSupportedException("不可实例化");
}
public static void main(String[] args) {
System.out.println(11);
}
Bean copy 性能比较
Apache Beanutils 性能最差 cglib性能最好 spring 的 BeanUtils 居中
JDK7 的 Try-with-resources
下面代码可以自动关闭实现了java.lang.AutoCloseable或java.io.Closeable的对象资源
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
桥接方法(bridge method)
https://blog.csdn.net/mhmyqn/article/details/47342577
GC选择
https://groups.google.com/a/jclarity.com/forum/#!topic/friends/0Ennhw9n0Hg http://eivindw.github.io/2016/01/08/comparing-gc-collectors.html
javax.annotation.processing.Processor 使用
https://www.race604.com/annotation-processing/
java interface 方法上声明的注解无法被实现类继承
多接口实现问题,所以interface 方法上声明的注解无法被实现类继承
https://stackoverflow.com/questions/4745798/why-java-classes-do-not-inherit-annotations-from-implemented-interfaces
分布式自增ID
twitter 雪花算法 snow flake
spring应用启动很慢
eureka在启动时会去查当前机器的域名,如果域名解析过慢,导致整个应用启动都很慢,将本机的ip和域名加到 /etc/hosts 里面,这样启动就快了,从 3min 缩短到 20s
UUID.randomUUID() 生成重复id问题
https://stackoverflow.com/questions/35050628/repeated-set-of-uuids-from-javas-uuid-randomuuid
protobuf 和 protostuff
protobuf 是与语言无关、平台无关的通信协议,需要写pb文件。
protostuff 是一个java类库,可直接对普通的javabean进行序列化和反序列化,支持多种序列化方式(protobuf, json, yaml, protostuff 等)
jpa 和 mybatis 的比较
http://www.spring4all.com/article/391
java 负数取模
先忽略负号,按照正数运算之后,被取模的数是正数结果就取正,反之取负。
- (-2)%5 = -2
- 2%(-5) = 2
- 5%(-2) = 1
- (-5)%2 = -1
jdk 1.7 concurrentHashMap 弱一致性
concurrentHashMap并不能完全替代HashTable,因为 HashTable 是强一致性,而concurrentHashMap是弱一致性
限流算法
- 计数器
- 漏桶算法
- 令牌桶算法: guava 的 RateLimiter提供了令牌桶算法实现
JDK8 Stream 并行处理
在jdk8中,可以调用 parallel() 方法使最终的终端操作变为 并行化 处理,那么JDK中是如何做的呢?有两种情况:
- 每个 Stream流 都使用 一个 新的线程池(那么多线程环境下,多个线程都使用 parallel 提高并行度,会不会导致线程爆炸,反而降低了并发效率呢?)
- 所有 Stream流 都使用 一个 共享的线程池 (那么多个线程同时使用 parallel,会不会导致 一个线程的Stream流提交的多线程任务过多,从而影响了另外一个毫不相干的线程的Stream流的parallel执行,使其阻塞呢?)
带着上面两个问题,调试查看Stream的parallel执行过程,发现所有Stream流的并行操作都是共享 java.util.concurrent.ForkJoinPool#common (工作线程默认为CPU个数) 这个线程池来进行并发操作的。所以也就是上面说的情况2.
tomcat 最大连接数
https://blog.csdn.net/quliuwuyiz/article/details/79979031
jdk8 比较器链式调用疑问
// 方法一
Comparator<List<Integer>> c1 = Comparator.comparing(List::size);
c1 = c1.reversed();
// 方法二
Comparator<List<Integer>> c2 = Comparator.comparing(List::size).reversed();
// 方法三
Comparator<List<Integer>> c3 = Comparator.comparing(List<Integer>::size).reversed();
使用方法二编码方式,它是无法通过编译的(报错:Not-static method cannot be referenced from a static context.),只有一和三可以通过编译。
详情:https://bugs.openjdk.java.net/browse/JDK-8190548
java 安全访问模式
https://www.ibm.com/developerworks/cn/java/j-lo-javasecurity/index.html
卫语句
卫语句就是把复杂的条件表达式拆分成多个条件表达式,比如一个很复杂的表达式,嵌套了好几层的if - then-else语句,转换为多个if语句,实现它的逻辑,这多条的if语句就是卫语句.
Java类加载器
System, current, context? Which ClassLoader should you use?
Do You Really Get Classloaders?
IBM开发者文档
https://www.ibm.com/developerworks/cn/
PicoContainer 实例化任意对象的框架
https://www.cnblogs.com/yaoxiaohui/archive/2009/03/08/1406228.html
JDBI,JOOQ
都是 持久层框架,类似于Mybatis,JDBI文档:传送门,JOOQ文档:传送门
使用 JOOQ的流式sql拼接来构建sql,使用JDBI绑定参数执行SQL, 例子
分布式事务
https://www.ktanx.com/blog/p/2862
volatile 分析
http://ifeve.com/volatile/
JVM栈异常信息优化
JVM中有个参数:OmitStackTraceInFastThrow,字面意思是省略异常栈信息从而快速抛出,那么JVM是如何做到快速抛出的呢?JVM对一些特定的异常类型做了Fast Throw优化,如果检测到在代码里某个位置连续多次抛出同一类型异常的话,C2会决定用Fast Throw方式来抛出异常,而异常Trace即详细的异常栈信息会被清空。这种异常抛出速度非常快,因为不需要在堆里分配内存,也不需要构造完整的异常栈信息.
字符集
http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
Little’s Law(利特尔法则)
在一个稳定的系统中,长时间观察到的平均顾客数量L,等于,长时间观察到的有效到达速率λ与平均每个顾客在系统中花费的时间之乘积,即L = λW
可用来估算 线程池等待队列 平均等待数量
浮点数表示法
float 和 double 采纳了 IEEE 754 标准(用科学记数法以底数为 2 的小数来表示浮点数)中所定义的单精度 32 位浮点数和双精度 64 位浮点数的格式
V=(-1)^s * M * 2^E (公式1) (1)(-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数。 (2)M表示有效数字,大于等于1,小于2。 (3)2^E表示指数位。 对于32位的float,s占1位,E占8位,M占32位,
float从左到右,第一位是符号位,2-9位共8位表示整数位,2的8-1次方等于128,后面23位是表示小数的,所以最大值是2^128-1。 double从左到右,第一位是符号位,2-12是共11位表示整数位,2的11-1次方等于1024。剩余20位表示小数,所以最大值是2^1024-1。
https://blog.csdn.net/lovelvyan/article/details/52300137
double和float都是精度:传送门
java中的编码
java每个char使用2个字节,采用unicode字符集,使用utf-16编码方式。
所以如果想在代码中使用超过2个字节表示的unicode字符(例如 0x1F344),则使用UTF-16进行表示(前一个字符表示为 \uD83C\uDF44).
相关文章: how does one show extended unicode > 0xFFFF
base64编码
http://www.ruanyifeng.com/blog/2008/06/base64.html
逃逸分析优化
以下代码,打开逃逸分析(-XX:+DoEscapeAnalysis)花费10ms左右,若关闭逃逸分析(-XX:-DoEscapeAnalysis)花费100ms左右
// -server -Xmx10m -Xms10m -XX:-DoEscapeAnalysis -XX:+PrintGC -Xss160k
public static void main(String[] args) {
// 设置 -XX:+DoEscapeAnalysis 做逃逸分析,在栈上分配空间
try {
long start = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
alloc();
}
System.out.println(System.currentTimeMillis() - start);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void alloc() {
byte[] b = new byte[2];
b[0] = 1;
}
字节序
- 大端字节序:高位字节在前,低位字节在后,这是人类读写数值的方法。
- 小端字节序:低位字节在前,高位字节在后。
设计模式
https://github.com/jpsoroulas/java8-patterns
接口方法参数上的注解无法被实现类对应方法的参数继承到, 方法同理
java 对象占多少个字节
深入分析Volatile的实现原理
Volatile 变量的写,在汇编层面会增加 lock 指令,lock前缀的指令在多核处理器下会引发了两件事情:
- 将当前处理器缓存行的数据会写回到系统内存。
- 这个写回内存的操作会引起在其他CPU里缓存了该内存地址的数据无效。
Compressed Oops
开启普通对象指针压缩: -XX:+UseCompressedOops , jdk8默认为 开启
HotSpot 指针压缩优化 :传送门
Oops : ordinary object pointer
What does the UseCompressedOops JVM flag do and when should I use it?
上面的问题回答中提出,指针压缩后引用是4个字节,可以管理32G内存,原因是:4个字段可以表示4G个地址,而JVM是使用8字节填充的,每个地址对少占8个字节,所以可以管理32G内存。
java线程的工作内存
线程的working memory是cpu的寄存器和高速缓存的抽象描述:现在的计算机,cpu在计算的时候,并不总是从内存读取数据,它的数据读取顺序优先级 是:寄存器-高速缓存-内存。
高速缓存又分为一级Cache(L1 Cache)和二级Cache(L2 Cache),L1 Cache集成在CPU内部,L2 Cache早期一般是焊在主板上,现在也都集成在CPU内部,常见的容量有256KB或512KB L2 Cache。(现在一些还有L3 Cache)
CLH 自旋锁
CLH(Craig, Landin, and Hagersten locks): 是一个自旋锁,能确保无饥饿性,提供先来先服务的公平性。
CLH锁也是一种基于链表的可扩展、高性能、公平的自旋锁,申请线程只在本地变量上自旋,它不断轮询前驱的状态,如果发现前驱释放了锁就结束自旋。
当一个线程需要获取锁时:
1.创建一个的QNode,将其中的locked设置为true表示需要获取锁
2.线程对tail域调用getAndSet方法,使自己成为队列的尾部,同时获取一个指向其前趋结点的引用myPred
3.该线程就在前趋结点的locked字段上旋转,直到前趋结点释放锁
4.当一个线程需要释放锁时,将当前结点的locked域设置为false,同时回收前趋结点
K8S 在线书籍
https://jimmysong.io/kubernetes-handbook/