代码精进之路
范学雷
前 Oracle 首席软件工程师,Java SE 安全组成员,OpenJDK 评审成员
38234 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 48 讲
结束语 (1讲)
代码精进之路
15
15
1.0x
00:00/00:00
登录|注册

23 | 怎么减少内存使用,减轻内存管理负担?

避免不必要的实例
枚举类型
无法修改的对象
不可变的类
使用单实例模式
避免使用原始数据类
减少实例的数量
减小实例的尺寸
减少内存使用
大数据、云计算、物联网的挑战
缓存的本意
亚马逊的改进请求
构造方法设计
getInstance()方法
使用更少的内存
缓存管理
Java内存管理能力
一起来动手
怎么减少内存使用,减轻内存管理负担?

该思维导图由 AI 生成,仅供参考

管理内存,不管是什么编程语言,向来都是一个难题。Java 语言能够长期领先的一个重要原因,就是它拥有强大的内存管理能力,并且这种能力还在不断地进化。然而,只依靠 Java 内在的内存管理能力,是远远不够的。
2018 年 9 月,亚马逊向 OpenJDK 社区提交了一个改进请求。这个改进涉及到一个问题,如果一个服务的缓存数量巨大,比如说有 10 万个连接会话,Java 的垃圾处理器要停滞几分钟,才能清理完这么巨大的缓存。而这几分钟的停滞,是不可忍受的事故。
这是一个值得我们关注的细节。缓存的本意,就是为了提高效率。然而,拥有过多的用户,过多的缓存,反而会让效率变低。
随着大数据、云计算以及物联网的不断演进,很多技术都面临着巨大的挑战。七八年前(2010 年左右),能解决 C10K(同时处理 1 万个用户连接)问题,感觉就可以高枕无忧了。现在有不少应用,需要开始考虑 C10M(同时处理 1 千万个用户连接)问题,甚至是更多的用户连接,以便满足用户需求。很多以前不用担心的问题,也会冒出来算旧账。
要想让内存使用得更有效率,我们还需要掌握一些成熟的实践经验。

使用更少的内存

提高内存使用最有效率的办法,就是使用更少的内存。这听起来像是废话,却也是最简单直接、最有用的办法。减少内存的使用,意味着更少的内存分配、更少的内存填充、更少的内存释放、更轻量的垃圾回收。内存的使用减少一倍,代码的效率会成倍地提升,这不是简单的线性关系。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文介绍了Java语言内存管理的重要性,并提出了减少内存使用、减轻内存管理负担的方法。首先,通过减少实例数量和减小实例尺寸来提高内存使用效率。其次,避免不必要的实例和使用单实例模式也是减少内存使用的有效方法。文章还强调了避免使用原始数据类和使用不可变的类来提高内存使用效率。这些方法可以有效减少内存分配、填充、释放和垃圾回收的开销,提高代码的执行效率。此外,还介绍了Java核心类库提供的生成不可更改的集合的方法,以及如何优化内存使用的技巧。总之,本文为Java开发者提供了重要的指导意义,帮助他们更好地管理内存,提高程序性能。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《代码精进之路》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(16)

  • 最新
  • 精选
  • pyhhou
    仅仅在这个代码基础上改的话: public HelloWords getInstance(String language) { if (language.equals(ENGLISH.language)) { return ENGLISH; } if (language.equals(MANDARIN.language)) { return MANDARIN; } throw IllegalArgumentException("This language doesn't exist"); } 用 private 来定义构造方法是为了防止类的使用者通过 new 的方式来产生新的对象,在这样的方式下,类的使用者只能通过类中的 static 对象中的 getInstance 方法来获取已经存在的对象,从而减轻了内存管理的负担 不用 private 来定义变量是因为类的使用者通过 getInstance 方法只能获取类的实例,也就是对象,但是对于对象里面的内容(language、greeting)还需进一步的获取; 用 final 去定义这些变量是为了防止类的使用者更改 static 对象中的内容,因为更改后会导致内容发生全局性的改变,从而和对象本身不匹配 但是个人认为这样的设计并没有很好的体现我们之前讲的 “简单直观” 的理念,首先这里存在着很深的嵌套,就是:类 -> static 对象 -> getInstance 方法 -> static 对象 -> 变量,这么分析看来设计并不直观,对于我来说,刚开始理解还比较的困难,所以可以考虑前面的将这里的 getInstance 方法改为 static 的方法,另外就是可以设一个 getGreeting 的方法去取得 instance 中的内容,用户通过函数 API 的方式获取内部信息而不是直接获取,在这种情况下我们可以将变量设为 private,这样比较好的隐藏内部实现,当然我们也可以使用之前提到的 enum 去实现: static enum Hellowords { ENGLISH ("English", "Hello"), MANDARIN ("Ni Hao"); final String language; final String greeting; private HelloWords(String language, String greeting) { this.language = language; this.greeting = greeting; } }

    作者回复: 你的留言里,有大量的深入思考,要点赞!

    2019-03-11
    19
  • 轻歌赋
    因为这是final修饰的变量,又是string,属性不可改变 可以考虑改成enum,或者是单例模式 单例模式推荐内部静态类持有的方式,相对更简单 如果使用容器化管理,例如spring,可以考虑注册成两个bean,通过规范约束不得创建,但是编程层面的约束力相对薄弱

    作者回复: 嗯,可以考虑使用内部静态类持有的方式。

    2019-02-25
    5
  • 天佑
    在编写代码时,如果能够引用,就坚决不要拷贝,老师您好,这样子做不会出现安全问题么,那入参防御性复制的使用场景是什么,有点糊涂了,期待老师答疑。

    作者回复: 有安全问题,就不算可以引用了。什么时候防御性复制,什么时候不用复制,我们在第三部分还会说这个问题。

    2019-03-11
    2
  • 君不得闲
    public static HelloWords getInstance(String language){ if ("English".equals(language)) { return ENGLISH; } if ("Mandarin".equals(language)) { return MANDARIN; } throw new IllegalStateException("This language is not supported"); } 构造方法没有实例化是为了避免使用者调用生成多实例,违背设计减少实例数量的初衷。 至于变量为什么不使用private关键字百思不得其解。因为如果没有修饰符修饰就代表只要是相同包内都可以对该类生成的实例的变量进行直接修改,但是final关键字又对这种修改做了限制,说明这两个是不可修改的常量,因为没有static修饰,说明这个常量是实例私有的,个人想法是已经用final了就没有必要用private修饰的多此一举了,就像接口的方法不用特意声明public abstract一样。

    作者回复: 异常类型使用IllegalArgumentException或者一个检查型异常,会好一点点。

    2019-02-25
    2
  • Geek_28d7fe
    单例模式破坏类的封装,现在很多开源代码尽量避免使用单例,是不是能不用单例就不用单例

    作者回复: 很多场景下,单例模式是优先选择。 比如enum就是单例模式的典范。所以,要看具体的场景,具体的状况。

    2019-05-21
    1
  • Sisyphus235
    内存管理这里说的大多是 Java 的语境,能够给一些通用的经验,如何在其他语言和框架下处理,而不是使用特定的包或者语言工具?

    作者回复: 这些原则同样适用于其他语言。你可以试试把它们运用到C++/C/GoLang等其他语言.

    2019-05-23
  • 天佑
    “在编写代码时,如果能够引用,就坚决不要拷贝” 这里不适用公共接口设计场景吧,考虑可变量的危害。

    作者回复: 是的。这里我加了个限定词“如果能够引用”,读到后面的文章,就知道这个限定词的作用了。外部接口,可变量要遵循审慎的原则,尽量拷贝或者规范明确标明不拷贝;内部实现的代码,如果清楚可变量的传递和变化不会捣乱,使用引用就行。

    2019-04-14
  • 徐题
    final修饰的类,它的成员变量也是final的吗?

    作者回复: 不是,除非成员变量使用了final修饰符。修饰符修饰什么,就对什么起作用,不要扩大范围。

    2019-03-06
  • 李米
    最好的优化就是不用,不用线程同步,不使用内存。老师的风格让我想起来奇葩说里的李诞:名画的最好归宿就是烧了。~老师技术不但实力强,还是个逗逼
    2019-12-07
    1
  • 往事随风,顺其自然
    构造器使用私有的,不允许实例化多个类,减少实例数量,变量没有私有化是因为string 不可变的类。
    2019-02-25
    1
收起评论
显示
设置
留言
16
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部