前几年,我一直期待 graalvm 把 java 编译成 native image 可以大幅减少 java 的内存占用,直到今天我用 graalvm 把我一个简单的 spring + spring mvc + mybatis plus + mysql 的小项目编译成 native 后(使用 g1gc ,配置最大堆内存 64m ),一测内存占用,好家伙,占用 184m ,优化了个寂寞,直接正常用 jvm 占用也就 200m 。启动速度确实快,285ms 即可完全启动。
我彻底死心了,java 对于请求量小的小型 web 项目内存消耗太大了,以后还是转投 nodejs 、golang 搞这种小项目吧,java 内存消耗太大了。
个人感觉云原生与微服务时代,java 官方对于资源占用问题解决速度还是太慢了,我阅读了 openjdk 社区的几乎所有的 jep ,发现起码未来 5 年,java 在解决内存占用问题上是不积极的。

内存占用问题,spring 得背大锅,换轻量级框架会好点

再提下官方进展:官方在推进 java 使用值类型,这可以提高 java 执行效率(变量分配到栈上而不是堆,降低 gc 压力,提高 cpu 执行效率),推测由于逃逸分析更方便,一定程度上会降低一点内存占用,这个预计下一个 lts 会上线。project leyden:探索渐进式约束 java 的动态特性换取更好的执行效率、性能占用、启动速度等问题,这个进度太慢了,起码得等到下下个 lts 。其它的看过也忘了,基本上语法上不会有大的改动,优化主要在 jvm\gc 上,没太多亮点。

内存从来都不是问题, 内存只会越来越便宜.

虽然如此,但总有内存敏感型场景

小内存推荐 Serial GC...

再耐心一点,未来可期。

我测试过,Serial GC 内存占用更大

已经结束辣😁,看看 jep ,未来 5 年内存占用问题是难有大的变化的

你的实际业务估计也就占用个 10-20M 内存,跟 java 本身关系不大,100M 内存也能跑很多业务+流量,就看你愿不愿意手撸 java 代码

手撸我还不如换成 golang 生态

我写 c#的 但我自己家里服务器部署的一些智能家居 api 我都用 golang 写的,镜像 17mb ,运行内存才几十 mb 不到,换 c#的镜像就得 250mb ,启动内存就得上百 mb

问题在于你用 spring 这种大型框架解决一个小问题,必然有大量的组件是无用占用

时间与空间不可兼得,更何况现在的内存便宜

spring 本身就不是个小项目

时间换空间:用你重写 go 的开发时间,换程序内存占用空间...

都上 spring 了,就别说省内存的事了…如果真的内存敏感,试试隔壁 php 或者 go 或者 node 或者别的啥,一样的内存,java 可能应用都起不来他们可能还能顺便跑个 MySQL啥场景用啥工具,用 java 干活说 java 吃内存,就好像说开大挂买菜说大挂废油一样…

都用 spring 了。就别在乎内存了。另外我一直不太懂,为什么要在小项目上追求启动速度

以前期待 graalvm 能让 spring 降降内存,结果降了个寂寞,以后我死了这条心了,用 java 就别想降内存

我这是测试,其实我是不在意其启动速度,但是云原生时代,启动速度快有很大的好处,对资源弹性伸缩比较好

可以选择迁移到 C# .NET 上面,内存占用更低,也比迁移到 node.js go 这些更简单。

更倾向于迁移到 golang ,nodejs ,c#感觉国内用得少

#3 Java 没有必要适用于任何场景。。。

自己写小程序不要用 asp.net core ,asp.net core 功能太多了,还有很多动态特性,杀鸡焉用牛刀,直接用轻量级的 http server ,然后再 AOT 编译,编译出来也就十几 MB ,运行内存也就几十 MB 。 我用 C# 整了个远程唤醒应用在我家路由器跑着。

c# 比 golang nodejs 还是多得多的

已经意识到了

感觉国内没啥公司用 c#吧,golang 起码字节主要再用,而且国人开源也给力

solon

#25 我感觉就算不算字节,用 Go 的都比用 C# 的多吧……

#17 首先你要搞清楚 graalvm spring java 是三个东西。应该是用 spring 就别想降内存。你完全可以使用纯 java 写个 webserver ,然后到时候再来说用 java 就别想降内存

java 有轻量级的 web 框架吧,有尝试过吗

你说的没错,我用 quarkus 做了个 demo ,比我上面那个项目还简单,内存占用编译成 native 是 57m

测了下 quarkus ,不过非常粗略

#22 asp.net core 也支持 native aot 了. 只做简单的几个 api, 不依赖第三方库的话, 编辑出来文件只有几百 K, 运行内占用十几 M

go 才多少人用呀 拿互联网来说 一个公司能有多少个 go 岗位(我拿前司来说 中国互联网百强企业 写 go 一般都是基础设施组 就寥寥那么几个人专职写 go 除了某几个头铁的 都不会用 go 来写业务的) 另外编程又不止互联网

之前我跟 OP 也有同样的期待,那这么说的话 graalvm 除了启动速度方面还有什么大提升的地方

要不试试 quarkus?docker run --cpus=0.1 --memory=20m --name quarkus -p 80:8080 yazi/sample:1.0__ _ _ --/ / / / / | / / //_/ / / / / -/ /_/ / /_/ / |/ , / ,< / /_/ /\ \ --\__\_\____/_/ |_/_/|_/_/|_|\____/___/ 2024-01-04 08:46:58,037 INFO [io.quarkus] (main) sample 1.0 native (powered by Quarkus 3.6.4) started in 0.284s. Listening on: 0.0.0.0:80802024-01-04 08:46:58,037 INFO [io.quarkus] (main) Profile prod activated. 2024-01-04 08:46:58,037 INFO [io.quarkus] (main) Installed features: [cdi, hibernate-orm, hibernate-reactive, kotlin, reactive-pg-client, resteasy-reactive, resteasy-reactive-jackson, smallrye-context-propagation, vertx]CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS185ccb037e19 quarkus 0.00% 12.16MiB / 20MiB 60.80% 993kB / 1.55MB 0B / 0B 42yazinnnn0@cs-679368844937-default ~ [SIGINT]> wrk -t4 -d1s -c100 localhost:80/helloRunning 1s test @ localhost:80/hello 4 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 127.19ms 114.59ms 430.17ms 55.63% Req/Sec 234.82 160.64 0.87k 78.57% 765 requests in 1.01s, 79.94KB readRequests/sec: 755.88Transfer/sec: 78.98KB简单试了下 demo, 容器可以给 20M 内存

java 写后端业务还是强,生态太猛了,golang 如果 5 年后生态发展起来,是会威胁到 java 的生存空间的

quarkus 我不是很熟,之前写了个 demo 占用 57m ,可能我没配置好,目前看来,spring 框架有点重,对内存占用不太好

这个大可放心 不会威胁到生存空间 go 和 java 的定位不一样 go 没办法像 C# java 一样高效

你编译了多久........

使用 Spring 这种「企业级」的框架注定了无法轻量。为特定的场景做合适的技术选型是必修课。

小型 web 项目用得着云原生 微服务吗内存 1g 的轻量服务器不够你跑 springboot ?

C#用的比你想象的多吧,游戏这边不少用的

这个内存占用和 java 无关, 大概率是 spring 等框架带来的占用.你如果手撸 servlet, 占用也很低..

我目前只发现启动速度确实有很大优势,但是目前上手门槛还是太高了,且不说很多框架完全没有适配 graalvm ,我为了让 mybatis plus 能够不报错启动做了一大堆适配工作,github 看了不少讨论,在我看来起码还得 3 年 java 生态才能适配好 graalvm ,企业大规模采用的话应该要到 5 年后了。graalvm 负面影响是牺牲了 java 的动态性,arthas 这种 debug 神器都没法用了

golang 弱弱的来吊打一下 :)狗头

linux 下编译得 5 分钟,之前 windows 下编译 8 分钟

确实是,以前我还有幻想,现在没了

你可以把我这个实验看成 java 如何应对内存敏感型场景

golang web 生态有待加强

是不是写 javaer 只会用 spring 全家桶啊?之前让同事帮忙写一个嵌入式的量产工具,需求是工人在 UI 填入设备序列号,通过 UDP 协议给设备,设备回复结果,超时就通过 UI 提示。等他交给我的时候启动日志就打印了一个大大的 SPRING

毕竟 spring 实在太方便了,其实 java 生态在你说的这个场景确实有更好的技术选型

NodeJS + Koa + Knex 表示一个有几十个接口和十几张表,每分钟访问量大约一两百次的小项目大概需要 80M 内存

nodejs 在请求量小的时候的内存占用还是少的

不好意思我的,其实我想说的是 Web 场景,游戏那块儿确实还得 C#

#50 只要不考虑内存什么的,现在写 Java 直接上 Spring Boot 完全没问题啊,Boot 提供了很多开箱即用的东西,没必要说“是不是写 javaer 只会用 spring 全家桶啊?”这种话吧;关于你的同事在“嵌入式”场景下用 Spring 这种重型 framework 可能确实不太妥,但我更倾向于这是使用者的问题

我觉得这个得看业务跑起来之后的占用,不是看刚启动的

要不试试 ktor?

云上的内存其实非常有限,越是大企业越在意成本。 越便宜的产品,消费者反而会越斤斤计较价格。总价 100w 的房子多 1w 少 1w 很多人不会有感觉,总价 10 块钱左右的拖鞋,很多人都会挑来跳去就为了省那一块钱

这玩意好使么?有没有实际使用的数据发来看看?

#30 openjdk.org/jeps/408 试一下 java-webserver 想要内存小就不要用成熟的框架

这个就算了,这个只能临时用用

手写 servlet,能不用的包就别用,使用 Serial 。应该能省下不少。

我也觉得,云厂商为了赚钱内存卖的比较贵,即便是如今内存价格已经降了很多的情况下

不觉得你的想法很矛盾吗,一边说内存敏感,一边又要上 spring你这不叫 java 应对内存敏感,而是 spring 内存占用测试

你跑起来只需要 200M ???我怎么感觉随便一个 java 项目不分配 2G 根本不敢上。。。

2g 有点夸张吧,你是依赖过多了吧,调整下最大堆内存大小,可以测试下最大堆内存调低到多少项目才无法启动

比如,线上 java 项目的 docker ,你敢不敢只分配 256MB 512MB 1G 就让跑。。。。

确实 springboot 项目 JVM 2G-20G 不等。8G 的居多。

不敢,个人项目倒是可以

不要嫌 Java 内存占用大,JVM 可是目前内存占用最小的 VM 。相比与其他编码语言,Java 内存占用大,是因为 VM ,而决定 VM 的是 GC 机制,这都跟它的解释性运行架构没关系,所以编译成 native ,并不能减少内存占用。

#55 注意是量产工具,量产工具都是运行在 pc 上面的,内存? who care ? 就是 udp 通信,肯定启一个 springboot 然后 CommandLineRunner 里面 循环发送 udp 就完事了

怼上数据库(postgres)后简单模拟了一下 quarkus 在有限内存的情况 implementation("io.quarkus:quarkus-hibernate-reactive") implementation("io.quarkus:quarkus-resteasy-reactive-jackson") implementation("io.quarkus:quarkus-hibernate-reactive-panache-kotlin") implementation("io.quarkus:quarkus-kotlin") implementation("io.quarkus:quarkus-reactive-pg-client")class Todo : PanacheEntity() { companion object : PanacheCompanion var title: String? = null var description: String? = null var completed: Boolean? = null (name = "due_date") var dueDate: LocalDate? = null (name = "created_at", updatable = false) var createdAt: LocalDate? = null (name = "updated_at") var updatedAt: LocalDate? = null}("todo")class TodoApi { fun getAll() = Todo.listAll() fun save(todo: Todo): Uni { if (todo.id == null) { return todo.persistAndFlush() } throw WebApplicationException("id shouldn't exist", 499) } ("{id}") fun getOne(@RestPath id: Long) = Todo.findById(id)}version: '3.8'services: postgres: deploy: resources: limits: memory: 100m cpus: "0.1" image: postgres:latest environment: POSTGRES_DB: yazinnnn POSTGRES_USER: yazinnnn POSTGRES_PASSWORD: yazinnnn sample: image: yazi/sample:1.0 deploy: resources: limits: memory: 20m cpus: "0.1" ports: - "80:8080" depends_on: - postgres environment: "QUARKUS_DATASOURCE_REACTIVE_URL": vertx-reactive:postgresql://postgres/yazinnnn➜ postgres wrk -t 12 -c 100 -d 10s localhost/todo 18:09:49Running 10s test @ localhost/todo 12 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 536.18ms 143.86ms 999.36ms 75.14% Req/Sec 16.39 10.27 80.00 71.69% 1750 requests in 10.09s, 3.31MB readRequests/sec: 173.39Transfer/sec: 335.78KB➜ postgres wrk -t 12 -c 100 -d 10s localhost/todo/1 18:10:03Running 10s test @ localhost/todo/1 12 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 256.09ms 78.20ms 499.31ms 84.83% Req/Sec 31.49 17.98 191.00 60.73% 3686 requests in 10.08s, 705.52KB readRequests/sec: 365.55Transfer/sec: 69.97KB

#72 看起来 quarkus 给 20m 就可以跑个基本的 crud 程序了话说在资源敏感的情况下, 不是该上 rust 吗?

k8s 容器环境的内存捉襟见肘

可以测试下 vert.x 吗, 这个估计占用也很小,几十 m

没用过,等个有缘人测试下

graalvm 是不是没法用数据库连接池? 之前好像是。

可以的,跟正常使用一样,graalvm 只是限制了反射和代理的使用,如果非要用到反射和代理,得通过 json 文件告知 graalvm

反过来想,是 spring 不适合小项目,小项目就用 go rust

谢谢,大概 10 个月之前折腾过一次,可能是 spring 或者连接池的原因,想弄成 native ,结果不行,就没深究了

可以看下这个项目,利用 spring 提供的 proxy 、reflect 钩子注册需要使用到代理、反射的地方,最终运行一个 native 程序

github.com/nieqiurong/mybatis-native-demo

遇到了一样的场景(使用 native 重构应用),虽然个人对这个结果是早有预见,但还是比较失落。正在分别使用 quarkus 和 rust 重构,看看是否能带来内存和性能上的极大提升。

quarkus 号称云原生 java

quarkus 可能会更好点,spring 内存占用可能还是优化不了

你先把你的 spring 扔了用轻量框架再说; spring 自己就是个内存大户

java 内存不是叫大 是非常大。一套 k8s 主节点所有服务才 1 个 G ,java 随便写点东西 2G 起步,不给多点 死给你看。有得必有失,根据应用场景选,java 作为企业级大杀器 大厂有钱使劲造 稳定就行

内存很值钱吗?

JEB 加载个微信 APK, 得上 128G 内存

Graal 也没有魔法啊,能优化优化速度完全是仗着把初始化好的 heap 存起来了。春天包含这老多东西,那内存不可能小啊

你猜为什么很多公司不愿意用 ELK

我就是因为嫌 elk 占用内存太大用了 loki+grafana+promtail 来做日志分析

小项目使用 go 也很方便。

早在 JDK 1.5 的时候我就觉得这内存吃不起啊,所以就玩起了 Python ,以及这两年的 Golang

内存使用和 graalvm 用不用关系不大,你自己 dump 下内存堆就可以了,spring 里面 jar 包太多了,native 后会直接被 graalvm 直接加载到内存里面,且一直不得释放,内存占用肯定下不来,小的 web 项目真没必要上 spring boot 全家桶,可以试试 github.com/94fzb/simplewebserver 这个库,内存 16m ,就启动的了,自己程序优化的好 32m ,就能流畅运行了

我打算试试 OpenObserve ,Rust 写的,采集程序可以用 iLogTail ,连 Kafka 都省了

速度从来都不是问题, 速度只会越来越快.

最近刚好把一个 springboot 的 iot 项目( 10 多个服务) 改造成 native ,累个半死,32c256g 机器 gradle 不开多线程要编 50 多分钟,开了也要 18 分钟

这个锅应该 spring 来接,或者其实不该接。内存敏感就不该选 spring 呢? vertx 、直接 netty 都能搞,或者写写 go :doge

有个问题啊, 没写过 java,无意间刷抖音刷到个视频说写 spring 用 mybatis orm 想输出 执行的 sql 语句,需要装一个 IDE 插件.....这东西配不出来么???还需要借助 IDE 才能实现??