Springboot开发的应用为什么这么占用内存
  HL7exJhKg9j2 2023年11月30日 27 0

Springboot开发的应用为什么这么占用内存


Java的原罪

Java 程序员比 c或者是c++程序员相比轻松了很多.
不要管理繁杂的内存申请与释放,也不用担心因为忘记释放内存导致很严重的内存泄漏. 

因为JAVA使用GC 垃圾回收的机制实现了内存的自动管理. 

自凡是自动管理, 就需要有单独的内存空间来存放相应的工具和管理数据. 就导致需要时用更多的内存

现阶段JVM的GC管理器关注点并不在于 如何减少内存的分配与消耗,
而是主要目的在于减少FullGC导致的STW, 避免会影响业务

因为内存越来越便宜,这也就导致了内存的使用更加泛滥. 

JAVA 本身就是运行与JVM虚拟机的, 本身就需要消耗一定的资源进行管理与优化. 
这是JAVA应用内存的最底层的原因之一.

Java内存管理的繁杂

1. JAVA运行时的是依赖于JVM进行源代码的解析与运行.
   运行JVM和JVM解析运行代码都需要内存.而且需要的往往很多. 
2. JAVA内存管理 大体上可以分为 堆区和非堆区
3. 非堆区解释起来比较复杂: 有直接内存, 有栈区, 有方法区, 有类加载器, GC,解释器,编译器,等等工具.
   每种工具都需要内存来存储. 比较多的是 方法区, 栈区, 直接内存. 
3.1 类被加载,编译后会把编译好的方法放到方法区, 这个里面一般至少会预留 240M左右的内存, 
   如果程序非常复杂,方法区应该适当扩容, 因为他的作用跟Oracle的shared pool类似.  缓存了编译优秀的方法
   如果空间不够,会被GC掉, 这样下次再调用时需要再次进行解析编译, 会浪费CPU周期和增加相应时间. 
3.2 直接内存, ERP应用并不像是科学计算, 他需要大量的输入输出, 需要大量的文件读写,数据库访问.
   java需要开辟很多内存通过类似于map的方式进行映射到file, 方便快速进行读取和写入以便提高性能. 
   如果是有的文件都需要加载到内存才能够进行读写的话, 堆区的压力会很大, GC会很大, 性能也会衰退
   所以还是有必要保留一些内存用于直接内存与系统,与数据库进行交互.
3.3 栈区, linux上面一个栈大约有1M内存的大小. 一般情况下一个java应用负载一些 200个左右的线程数量是很正常的
   这就意味着至少有200M左右的内存作为栈内存进行使用. 
3.4 GC,类加载,解释器,编译器. 工具都需要内存进行处理, 很多类加载器还需要跟踪类的调用次数. GC需要记录类的层级
    这些工具都需要使用内存进行运行和管理数据.
3.5 在一个大型应用中, 非堆区超过1G内存也是很正常的. 不能小看非堆区内存, 不能过量的扩大堆区
    需要避免出现非地区导致的OOM或者是栈溢出的问题. 

4.1 堆区内存就比较好理解了. 提高JAVA性能的几个方法里面一直有加大堆区, 改用好的GC算法等.
    可以简单理解为方法区存放的是类的一些定义, 堆区存放的是类的实例化的对象.
    方法区内的类和方法 在堆区都会有多倍甚至是无数倍的实例化对象. (单例的话会少一些)

    堆区中还有一些简单的数组, 一些dataset 查询展示的对象, 文件实例化的格式化数据等等内容
    堆区如果过小, 会不停地进行GC, 一方面导致CPU增加,一方面会导致产品相应变慢, 

5. 所有的性能都不是平白无故产生的. 要么是空间换时间, 要么是时间换空间. 
   java明显就是使用空间换时间的一种方法. 
   与linux的buffer cache 和 oracle的 db buffer 一样. 缓存到内存是提高性能的最便宜的方法. 

内存不是越小越少, 如果仅是进行一些计算,可以使用低内存, 高CPU占比
但如果是重流程,重数据的业务应用, 建议流出足够的内存进行缓存, 避免GC来提高性能.

Springboot的推波助澜

springboot开创性的AOP和IOC 会导致springboot的框架需要自行管理很多内容. 
bean的实例化和管理不仅仅会导致启动变慢, 也会导致内存的更多使用. 

springboot本身框架里面就会有比较多的组件, 每种组件都需要使用内存进行存储和实例化
这就增加了内存的使用. 

IOC实际上解放了开发是 进行 new object的过程, 这也导致框架内必须存储好 bean(懒加载除外)
类或者是bean多了 管理和寻找都会成为课题, 为了性能不得不启用更加负责的内存, 索引等类型导致内存使用量增加.

ERP应用的特定场景

ERP 的核心是数据,业务和流程.
这三者都需要大量的内存进行处理

一个大型的查询,虽然可以走到数据库分页, 但是内存中不可避免的出现大量的dataset等对象用于存储和展示.
虽然很多数据可以共享.
但是ERP严格要求数据权限的高标准
导致很多内存对象无法进行共享,不然会出现数据泄密
这就导致在高并发情况下内存的使用量可能会翻倍的激增. 

产品的流程特别复杂时需要缓存各个流程的多个节点信息,便于展示和直接使用
每多一个节点的展示,需要的内存就会更加的多. 

ERP还有很多打印和渲染的需求, 因为不能到客户端渲染(很难加水印,并且篡改非常简单)
会导致服务端的内存大量增加.

现在ERP为了更加好看, 和更加安全往往有很多优秀的特性.  特性都是需要花钱和内存的, 这会恶化内存的使用.

快速响应的要求

在很多审批和展示的环节领导要求越来越高, 甚至要求集团层次的查询要秒级出结果
这其实是很难的. 唯一的解决方案只能是预读和缓写

预读的话需要将要展示的数据缓存到java的内存
缓写的话需要增加各种措施来保证一致性. 

虽然可以拆分SU来进行内存的拆解
但是上面谈到的几点内存使用基本上是无法避免的

数据库是及其昂贵的

现阶段大部分ERP还都是使用集中式的数据库来存储数据
集中式的数据库是非常金贵的资源
在高并发大数据量的情况下几乎是很难实现快速响应的. 

为了减少对数据库的以来. JAVA应用可以缓存很多数据进入内存中.
虽然那也可以使用redis, 消息队列等方式进行缓解, 但是redis和消息队列的过度使用会是性能杀手

适当的内存使用对性能,稳定性,尤其是数据库的稳定性是非常有裨益的.



【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月30日 0

暂无评论

推荐阅读
HL7exJhKg9j2