找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

428

积分

1

好友

48

主题
发表于 3 天前 | 查看: 8| 回复: 0

图片

Java应用的性能瓶颈,往往不在于语言本身,而在于编码实践。养成良好的习惯,能显著提升程序效率。

1. 在合适的场景使用单例模式

单例模式通过减少对象创建来节约资源、提升加载效率。它主要适用于三种场景:

  • 控制资源的并发访问。
  • 控制实例数量,节约资源。
  • 在不建立直接关联的模块间实现数据共享。

2. 谨慎使用静态变量

当一个对象被静态变量引用时,只要其所属的类未被卸载,该对象便常驻内存,难以被垃圾回收(GC)。这会增加内存占用,直到程序终止。更多关于Java内存管理的知识,有助于理解此处的原理。

public class A {
    private static B b = new B(); // b的生命周期与A类同步
}

3. 避免过度创建对象

在循环或高频调用的方法中频繁new对象,会大量消耗创建与垃圾回收的时间。应在可控范围内最大化重用对象,或考虑使用基本类型、数组替代对象。

4. 善用final修饰符

final修饰的类不可继承,其所有方法隐含为final。编译器会尝试内联(inline)final方法,这平均能带来约50%的性能提升。例如,将简单的getter/setter方法设为final原始示例

class MAF {
    public void setSize (int size) {
        _size = size;
    }
    private int _size;
}

优化后

class DAF_fixed {
    final public void setSize (int size) {
        _size = size;
    }
    private int _size;
}

5. 优先使用局部变量

方法参数和局部变量存储在栈(Stack)中,访问速度快。而实例变量、静态变量等在堆(Heap)中分配,访问相对较慢。

6. 区分基本类型与包装类型

基本类型在栈上处理,效率高;包装类型是堆中的对象。在集合类等需要对象的场景使用包装类型,其他计算场景提倡使用基本类型。

7. 减小同步范围

同步synchronized会带来较大开销,甚至可能导致死锁。应尽量减少同步代码块的范围,并优先考虑使用方法同步而非代码块同步,以降低锁的粒度。

8. 避免使用finalize方法进行资源清理

依赖finalize()方法清理资源会增加GC负担,严重影响程序性能。资源的释放应通过显式调用close()等方法或在finally块中完成。

9. 字符串创建的优化

String str = “hello”; // 推荐,利用JVM字符串常量池
String str = new String(“hello”); // 不推荐,额外创建char[]对象

第二种方式会额外生成一个底层的char[]数组。

10. 非线程安全场景使用高效集合

在多线程安全无虞的情况下,应优先使用HashMapArrayList,而非其线程安全但性能较低的旧版替代品HashtableVector

11. 合理初始化HashMap容量

创建HashMap时,应根据预估容量合理设置初始大小(initialCapacity)和负载因子(loadFactor),避免多次扩容(rehash)。

public HashMap(int initialCapacity, float loadFactor); // 充分利用此构造函数

12. 减少循环内的重复计算

将循环中不变的条件计算提取到循环外。

// 不推荐
for (int i = 0; i < list.size(); i++)

// 推荐
for (int i = 0, len = list.size(); i < len; i++)

13. 延迟对象创建

只在真正需要时才创建对象。

// 不推荐
A a = new A();
if (i == 1) {
    list.add(a);
}

// 推荐
if (i == 1) {
    A a = new A(); // 需要时再创建
    list.add(a);
}

14. 在finally块中释放资源

确保资源(如I/O流、数据库连接)在任何情况下都能被正确关闭,避免资源泄漏。

// 示例
try {
    // 获取和使用资源
} finally {
    // 确保资源被关闭
}

15 & 16. 使用移位代替乘除

对于乘以或除以2的幂次方运算,使用移位操作效率更高。但需添加注释以增强可读性。

int num = a / 4;  // -> a >> 2
int num = a * 8;  // -> a << 3

17. 为StringBuffer指定初始容量

默认容量(16)不够时,StringBuffer会进行耗时的扩容和数据拷贝。预先估算大小可避免此开销。

18. 适时置null释放大对象引用

在方法中,局部引用变量通常随方法结束而失效。但若方法后半段有耗时或大内存操作,可显式将不再使用的对象引用置为null,以助GC尽早回收。

19. 避免使用二维数组

二维数组占用的内存空间远大于一维数组。

20. 慎用split方法

String.split()因支持正则而效率较低。高频调用时可考虑用StringUtils.split或缓存结果。在大数据处理场景中,此类优化尤为关键,更多技巧可参考大数据相关内容。

21. ArrayList与LinkedList的选择

  • ArrayList:基于数组,随机访问快(O(1)),但中间插入/删除慢(需移动元素)。
  • LinkedList:基于链表,插入/删除快(O(1)),但随机访问慢(需遍历)。

根据主要操作类型选择。

22. 使用System.arraycopy()复制数组

System.arraycopy()是原生方法,远比循环复制数组高效。

23. 缓存常用对象

对频繁使用的对象进行缓存,可使用容器或第三方缓存库(如EhCache、Oscache),但需注意防止缓存占用过多内存。

24. 避免超大内存分配

堆内存碎片化后,分配大块连续内存会变得困难,可能导致分配失败。

25. 异常创建的代价

创建异常需要生成完整的栈跟踪(Stack Trace),开销很大。应仅在异常情况下使用,避免在性能关键路径上频繁创建异常。

26. 重用对象,特别是String

字符串拼接应使用StringBufferStringBuilder,避免生成大量中间String对象。

27. 避免重复初始化变量

JVM会为成员变量设置默认值(0, null, false等)。在构造函数中调用方法进行初始化需谨慎,防止因对象未完全初始化而抛空指针。

// 不推荐
public int state = this.getState(); // getState()可能依赖未初始化的成员
// 推荐在init()方法中赋值

28. SQL语句使用大写(Java+Oracle场景)

在Oracle数据库中,将内嵌的SQL关键字写为大写,可减轻其解析器的负担。

29. 及时关闭资源

数据库连接、I/O流等使用后必须立即关闭,释放系统资源。

30. 手动辅助GC

对于大对象或使用完毕的对象,可将其引用显式设为null,向GC提示回收时机,尤其是在可能发生内存泄漏的场景。

31. 同步机制的选择

与方法同步相比,精确控制的代码块同步通常更好。但在简单场景下,使用方法同步可使代码更简洁。

32. Try/Catch置于循环外

try-catch放在循环外部,避免在每次迭代中都进行异常处理结构的构造。

33. 为StringBuffer预设容量

默认容量16往往不够,提前设置合理的初始容量可避免多次扩容和数据拷贝。

34. 合理使用Vector

  • 添加元素:默认容量10,扩容时复制全部元素。
  • 插入元素:vector.add(index,obj)会导致后续元素后移。
  • 删除元素:删除末尾元素remove(size()-1)比删除头部元素开销小。
  • 删除所有元素:使用removeAllElements()
  • 按对象删除:vector.remove(obj)比先查索引再删除高效。

35. 考虑使用clone()替代new

对于实现了Cloneable接口的对象,使用clone()方法创建实例不会调用构造函数,在某些场景下比new更快(如原型模式)。

private static Credit BaseCredit = new Credit();
public static Credit getNewCredit() {
    return (Credit) BaseCredit.clone(); // 不调用构造函数
}

36. 高效遍历HashMap

使用EntrySet进行遍历,直接获取键和值,效率高于先取keySetget(key)

Map<String, String[]> paraMap = new HashMap<>();
for (Entry<String, String[]> entry : paraMap.entrySet()) {
    String key = entry.getKey();
    String[] value = entry.getValue();
}

37. 数组(Array) vs ArrayList

  • Array:定长,效率最高。
  • ArrayList:动态扩容,使用灵活但有效能损耗。

38. 单线程首选HashMap、ArrayList

在无并发需求的场景,使用非同步的HashMapArrayList而非HashtableVector

39. StringBuffer与StringBuilder的选择

  • StringBuffer:线程安全,性能稍低。
  • StringBuilder:非线程安全,性能提升约10%-15%。 在非并发场景下,可使用StringBuilder;若涉及线程安全,StringBuffer是更稳妥的选择。

40. 多用静态方法

无需访问对象成员(非static)的方法,可声明为static。静态方法调用更快,且能明确表明该方法不依赖或改变对象状态。

性能优化是时间、空间与代码可维护性间的权衡。以上技巧需根据实际业务场景灵活运用,方能达到最佳效果。




上一篇:Python Twisted异步网络框架实战:构建高并发服务器与Web应用指南
下一篇:死锁四大必要条件详解:并发编程中的预防与避坑指南
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区(YunPan.Plus) ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-7 04:51 , Processed in 0.079664 second(s), 37 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 CloudStack.

快速回复 返回顶部 返回列表