《Java程序优化》读书笔记
2021-04-24 11:11:58 0 举报
AI智能生成
做java也很久了,自己也积累了一些代码优化方面的心得,一个好的代码是体现程序员水平的最直观体现,下面来看一下代码方面比较常见的优化点 (本文在书写过程中也参考了一些其他文章,在这...
作者其他创作
大纲/内容
引用类型
强引用 - FinalReference
可以直接访问目标对象
所指向的对象在任何时候都不会被系统回收。JVM宁愿抛出OOM异常,也不回收强引用所指向的对象
可能导致内存泄漏
软引用 - SoftReference
一个持有软引用的对象,不会很快被JVM回收,JVM会根据当前堆的使用情况来判断何时回收。当堆使用率临近阙值时,才会去回收软引用对象。
弱引用 - WeakReference
系统gc时,只要发现弱引用,不管系统堆空间是否足够,都会将对象进行回收
垃圾回收的线程通常优先级别很低,并不一定很快地发现持有弱引用的对象
虚引用 - PhantomReference
一个持有虚引用的对象,和没有引用几乎是一样的,随时都可能被垃圾回收器回收
作用在于跟踪垃圾回收过程,清理被销毁对象的相关资源
WeakHash Map
弱引用的一种类型应用,可以作为简单的缓存表解决方案
内部实现:Entry继承扩展了WeakReference
有助于改善性能的技巧
慎用异常
使用局部变量
位运算代替乘除法
替换switch
一维数组代替二维数组
提取表达式
展开循环
布尔运算符代替位运算
使用System.arrayCopy()数组复制
使用Buffer进行I/O操作
使用clone()代替new
静态方法替代实例方法
字符串优化
String对象
3个基本特点
不变性 - 指对象一旦创建,则不能在对它进行改变。
针对常量池的优化 - 两个对象拥有相同值时,他们只引用常量池中的同一拷贝
类的final定义 - 有助于虚拟机寻找机会,内联所有的final方法,从而提高系统效率
subString()方法的内存泄漏
字符串分割和查找
split
StringTokenizer
indexOf() && subString()
charAt() - 判断字符串是否为指定开头或者结尾
StringBuffer和StringBuilder
String常量的累加操作 - Java在编译时就做了充分的优化。
String变量的累加操作 - Java在编译的时候会转StringBuilder来累加。
构建超大的String对象 - 编辑器不一定够聪明
StringBuffer和Stringbuilder的选择
容量参数
核心数据结构
List
三种数据结构
ArrayList
Vector
LinkedList
元素内容
前驱表项
后驱表项
增加元素到列表尾端
ArrayList添加元素的时候,会去判断容量是否满足,不满足进行容量扩容。扩容到原始容量的1.5倍,采用system.arraycopy方法复制数组。
LinkedList内部采用链表的最后端,没有扩容操作
增加元素到列表任意位置
ArrayList需要进行重新排列,而LinkedList尾部插入数据和任意位置插入数据是一样,不会导致性能下降
删除任意位置元素
ArrayList删除需要进行数组重组,删除越前面的数据,开销越大。删除越后面的数据,开销越小。
LinkedList删除指定位置的元素,会通过index和size比较。如果删除的位置处于前半段,则从前往后找,若其位置处于后半段,则从后往前查找。效率比较低
容量参数
有效地评估ArrayList数组大小初始化值的情况下,指定容量大小能对其性能有比较大的提升
遍历列表
forEach
迭代器
for
Map
HashMap - 无序的
高性能
hash算法必须是高效的
hash值到内存地址的算法是快速的
根据内存地址可以直接取得对应的值
hash冲突
新的Entry以来会被安放在对应的索引下标内,并替换原来的值,同时,为了保证旧值不会丢失,会将新的Entry的next指向旧值。
基于HashMap的实现机制,只要hashCode()和hash()方法实现得足够好,能够尽可能地减少冲突的产生,对于HashMap的操作几乎等价于对数组的随机访问操作
容量参数
默认情况下,初始化长度为16,负载因子为0.75
负载因子=元素个数/内部数组总大小
内部还定义了一个threshold变量,定义为当前数组总容量和负载因子的乘积,表示HashMap的阙值
设置初始化大小和负载因子,可以有效减少Hash Map的扩容次数
LinkedHashMap - 有序的
提供两种类型的顺序
元素插入时的顺序 - false
最近访问的顺序 - true
设置accessOrder属性为true,采用迭代器的方式访问元素会报ConcurrentModificationException,因为get()方法会对数组进行重排
TreeMap
能够对元素进行排序
两种方式
构造函数中注入一个Comparator
使用一个实现了Comparable接口的key
Set
HashSet -- > HashMap
LinkedHashSet --- > LinkedHashMap
TreeSet ---> TreeMap
优化集合访问
分离循环中被重复调用的代码
省略相同的操作
减少方法调用
RandomAccess接口
标志接口,本身没有提供任何方法,任何实现
主要目的是标识那些可支持快速随机访问的List实现
任何一个基于数组的List都实现了此接口
使用NIO提升性能
特性
为所有的原始类型提供(Buffer)缓存支持
使用Java.nio.charset.Charset作为字符集编码解决方案
增加通道(Channel)对象,作为新的原始I/O抽象
支持缩合内存映射文件的文件访问接口
提供了基于Selector的异步网络I/O
两个重要的组件
缓冲Buffer - 连续的内存块, 数据的中转地
通道Channel - 表示缓存数据的源头或者目的地
Buffer
3个重要参数
位置 - position
容量 - capacity
上限 - limit
相关操作
allocate()从堆中分配缓冲区,或者从一个既有数组中创建缓冲区
重置和清空缓冲区
rewind
clear
flip
读/写缓冲区
get
put
标志缓冲区
mark用于记录当前的位置
reset用于恢复到mark所在的位置
复制缓冲区
duplicate
缓冲区分片
slice
只读缓冲区
asReadOnlyBuffer 保证核心数据的安全
文件映射内存
FileChannel.map
处理结构化数据 - 散射和聚集
ScatteringByteChannel
GatheringByteChannel
直接内存访问 - DirectBuffer
DirectBuffer继承自ByteBuffer
普通的ByteBuffer仍然在JVM堆上分配空间,受到最大堆的限制。而DirectBuffer直接分配在物理内存中。
DirectBuffer的读取性能优于ByteBuffer,但是对于创建和效率性能比较差
0 条评论
下一页