前几年,我一直期待 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 在解决内存占用问题上是不积极的。
1
keepRun OP 再提下官方进展:
官方在推进 java 使用值类型,这可以提高 java 执行效率(变量分配到栈上而不是堆,降低 gc 压力,提高 cpu 执行效率),推测由于逃逸分析更方便,一定程度上会降低一点内存占用,这个预计下一个 lts 会上线。 project leyden:探索渐进式约束 java 的动态特性换取更好的执行效率、性能占用、启动速度等问题,这个进度太慢了,起码得等到下下个 lts 。 其它的看过也忘了,基本上语法上不会有大的改动,优化主要在 jvm\gc 上,没太多亮点。 |
2
bthulu 315 天前
内存从来都不是问题, 内存只会越来越便宜.
|
4
salmon5 315 天前
小内存推荐 Serial GC...
|
5
kneo 315 天前
再耐心一点,未来可期。
|
8
xiangyuecn 315 天前
你的实际业务估计也就占用个 10-20M 内存,跟 java 本身关系不大,100M 内存也能跑很多业务+流量,就看你愿不愿意手撸 java 代码
|
9
keepRun OP @xiangyuecn 手撸我还不如换成 golang 生态
|
10
StoneHuLu 315 天前
我写 c#的 但我自己家里服务器部署的一些智能家居 api 我都用 golang 写的,镜像 17mb ,运行内存才几十 mb 不到,换 c#的镜像就得 250mb ,启动内存就得上百 mb
|
11
LykorisR 315 天前 9
问题在于你用 spring 这种大型框架解决一个小问题,必然有大量的组件是无用占用
|
12
sephiroka 315 天前
时间与空间不可兼得,更何况现在的内存便宜
|
13
chunqicoder 315 天前 1
spring 本身就不是个小项目
|
14
icyalala 315 天前
时间换空间:用你重写 go 的开发时间,换程序内存占用空间...
|
15
chendy 315 天前 19
都上 spring 了,就别说省内存的事了…
如果真的内存敏感,试试隔壁 php 或者 go 或者 node 或者别的啥,一样的内存,java 可能应用都起不来他们可能还能顺便跑个 MySQL 啥场景用啥工具,用 java 干活说 java 吃内存,就好像说开大挂买菜说大挂废油一样… |
16
ChaYedan666 315 天前
都用 spring 了。就别在乎内存了。
另外我一直不太懂,为什么要在小项目上追求启动速度 |
18
keepRun OP @ChaYedan666 我这是测试,其实我是不在意其启动速度,但是云原生时代,启动速度快有很大的好处,对资源弹性伸缩比较好
|
19
INCerry 315 天前
可以选择迁移到 C# .NET 上面,内存占用更低,也比迁移到 node.js go 这些更简单。
|
22
INCerry 315 天前 1
|
26
wxyrrcj 315 天前
solon
|
28
qwertty01 315 天前 4
@keepRun #17 首先你要搞清楚 graalvm spring java 是三个东西。应该是用 spring 就别想降内存。你完全可以使用纯 java 写个 webserver ,然后到时候再来说用 java 就别想降内存
|
29
Lambdua 315 天前
java 有轻量级的 web 框架吧,有尝试过吗
|
32
clorischan 315 天前 1
|
33
INCerry 315 天前 1
@keepRun go 才多少人用呀 拿互联网来说 一个公司能有多少个 go 岗位(我拿前司来说 中国互联网百强企业 写 go 一般都是基础设施组 就寥寥那么几个人专职写 go 除了某几个头铁的 都不会用 go 来写业务的) 另外编程又不止互联网
|
34
Plutooo 315 天前
之前我跟 OP 也有同样的期待,那这么说的话 graalvm 除了启动速度方面还有什么大提升的地方
|
35
yazinnnn0 315 天前
要不试试 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: http://0.0.0.0:8080 2024-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 PIDS 185ccb037e19 quarkus 0.00% 12.16MiB / 20MiB 60.80% 993kB / 1.55MB 0B / 0B 42 yazinnnn0@cs-679368844937-default ~ [SIGINT]> wrk -t4 -d1s -c100 http://localhost:80/hello Running 1s test @ http://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 read Requests/sec: 755.88 Transfer/sec: 78.98KB 简单试了下 demo, 容器可以给 20M 内存 |
39
hakr 315 天前
你编译了多久........
|
40
28Sv0ngQfIE7Yloe 315 天前
使用 Spring 这种「企业级」的框架注定了无法轻量。为特定的场景做合适的技术选型是必修课。
|
41
ddkk1112 315 天前
小型 web 项目用得着云原生 微服务吗
内存 1g 的轻量服务器不够你跑 springboot ? |
42
28Sv0ngQfIE7Yloe 315 天前
@gitrebase C#用的比你想象的多吧,游戏这边不少用的
|
43
BBCCBB 315 天前 1
这个内存占用和 java 无关, 大概率是 spring 等框架带来的占用.
你如果手撸 servlet, 占用也很低.. |
44
keepRun OP @Plutooo 我目前只发现启动速度确实有很大优势,但是目前上手门槛还是太高了,且不说很多框架完全没有适配 graalvm ,我为了让 mybatis plus 能够不报错启动做了一大堆适配工作,github 看了不少讨论,在我看来起码还得 3 年 java 生态才能适配好 graalvm ,企业大规模采用的话应该要到 5 年后了。
graalvm 负面影响是牺牲了 java 的动态性,arthas 这种 debug 神器都没法用了 |
45
coinbase 315 天前
golang 弱弱的来吊打一下 :)狗头
|
50
yolee599 315 天前
是不是写 javaer 只会用 spring 全家桶啊?之前让同事帮忙写一个嵌入式的量产工具,需求是工人在 UI 填入设备序列号,通过 UDP 协议给设备,设备回复结果,超时就通过 UI 提示。等他交给我的时候启动日志就打印了一个大大的 SPRING
|
52
Cat7373 315 天前
NodeJS + Koa + Knex 表示一个有几十个接口和十几张表,每分钟访问量大约一两百次的小项目大概需要 80M 内存
|
55
gitrebase 315 天前
@yolee599 #50 只要不考虑内存什么的,现在写 Java 直接上 Spring Boot 完全没问题啊,Boot 提供了很多开箱即用的东西,没必要说“是不是写 javaer 只会用 spring 全家桶啊?”这种话吧;关于你的同事在“嵌入式”场景下用 Spring 这种重型 framework 可能确实不太妥,但我更倾向于这是使用者的问题
|
56
fuckshiter 315 天前
我觉得这个得看业务跑起来之后的占用,不是看刚启动的
|
57
Cabana 315 天前 1
|
58
abcbuzhiming 315 天前
@bthulu 云上的内存其实非常有限,越是大企业越在意成本。
@ChaYedan666 越便宜的产品,消费者反而会越斤斤计较价格。总价 100w 的房子多 1w 少 1w 很多人不会有感觉,总价 10 块钱左右的拖鞋,很多人都会挑来跳去就为了省那一块钱 |
60
qwertty01 315 天前
@keepRun #30 https://openjdk.org/jeps/408 试一下 java-webserver 想要内存小就不要用成熟的框架
|
62
Richared 315 天前
手写 servlet,能不用的包就别用,使用 Serial 。应该能省下不少。
|
63
keepRun OP @abcbuzhiming 我也觉得,云厂商为了赚钱内存卖的比较贵,即便是如今内存价格已经降了很多的情况下
|
65
lambdaq 315 天前
你跑起来只需要 200M ???我怎么感觉随便一个 java 项目不分配 2G 根本不敢上。。。
|
68
salmon5 315 天前
确实 springboot 项目 JVM 2G-20G 不等。8G 的居多。
|
70
nothingistrue 315 天前 1
不要嫌 Java 内存占用大,JVM 可是目前内存占用最小的 VM 。
相比与其他编码语言,Java 内存占用大,是因为 VM ,而决定 VM 的是 GC 机制,这都跟它的解释性运行架构没关系,所以编译成 native ,并不能减少内存占用。 |
71
morgan1freeman 315 天前
@gitrebase #55 注意是量产工具,量产工具都是运行在 pc 上面的,内存? who care ? 就是 udp 通信,肯定启一个 springboot 然后 CommandLineRunner 里面 循环发送 udp 就完事了
|
72
yazinnnn0 315 天前
怼上数据库(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") @Entity class Todo : PanacheEntity() { companion object : PanacheCompanion<Todo> var title: String? = null var description: String? = null var completed: Boolean? = null @Column(name = "due_date") var dueDate: LocalDate? = null @Column(name = "created_at", updatable = false) var createdAt: LocalDate? = null @Column(name = "updated_at") var updatedAt: LocalDate? = null } @Path("todo") class TodoApi { @GET fun getAll() = Todo.listAll() @POST fun save(todo: Todo): Uni<Todo> { if (todo.id == null) { return todo.persistAndFlush<Todo>() } throw WebApplicationException("id shouldn't exist", 499) } @GET @Path("{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 http://localhost/todo 18:09:49 Running 10s test @ http://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 read Requests/sec: 173.39 Transfer/sec: 335.78KB ➜ postgres wrk -t 12 -c 100 -d 10s http://localhost/todo/1 18:10:03 Running 10s test @ http://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 read Requests/sec: 365.55 Transfer/sec: 69.97KB |
74
yalin 315 天前
k8s 容器环境的内存捉襟见肘
|
75
byte10 315 天前 1
可以测试下 vert.x 吗, 这个估计占用也很小,几十 m
|
77
bjfane 315 天前
graalvm 是不是没法用数据库连接池? 之前好像是。
|
78
keepRun OP @bjfane 可以的,跟正常使用一样,graalvm 只是限制了反射和代理的使用,如果非要用到反射和代理,得通过 json 文件告知 graalvm
|
79
knightdf 315 天前
反过来想,是 spring 不适合小项目,小项目就用 go rust
|
81
keepRun OP @bjfane 可以看下这个项目,利用 spring 提供的 proxy 、reflect 钩子注册需要使用到代理、反射的地方,最终运行一个 native 程序
|
82
keepRun OP |
83
ufan0 315 天前
遇到了一样的场景(使用 native 重构应用),虽然个人对这个结果是早有预见,但还是比较失落。
正在分别使用 quarkus 和 rust 重构,看看是否能带来内存和性能上的极大提升。 |
84
chaofanx 315 天前 via Android
quarkus 号称云原生 java
|
86
kenvix 315 天前
你先把你的 spring 扔了用轻量框架再说; spring 自己就是个内存大户
|
87
buffzty 315 天前
java 内存不是叫大 是非常大。一套 k8s 主节点所有服务才 1 个 G ,java 随便写点东西 2G 起步,不给多点 死给你看。
有得必有失,根据应用场景选,java 作为企业级大杀器 大厂有钱使劲造 稳定就行 |
88
itning 315 天前
内存很值钱吗?
|
89
VYSE 315 天前
JEB 加载个微信 APK, 得上 128G 内存
|
90
iseki 315 天前
Graal 也没有魔法啊,能优化优化速度完全是仗着把初始化好的 heap 存起来了。春天包含这老多东西,那内存不可能小啊
|
93
cabing 315 天前
小项目使用 go 也很方便。
|
94
GeekGao 315 天前
早在 JDK 1.5 的时候我就觉得这内存吃不起啊,所以就玩起了 Python ,以及这两年的 Golang
|
95
90xchun 315 天前 via Android
内存使用和 graalvm 用不用关系不大,你自己 dump 下内存堆就可以了,spring 里面 jar 包太多了,native 后会直接被 graalvm 直接加载到内存里面,且一直不得释放,内存占用肯定下不来,小的 web 项目真没必要上 spring boot 全家桶,可以试试 https://github.com/94fzb/simplewebserver 这个库,内存 16m ,就启动的了,自己程序优化的好 32m ,就能流畅运行了
|
97
wangtian2020 315 天前
速度从来都不是问题, 速度只会越来越快.
|
98
saberscarlet 315 天前 via Android
最近刚好把一个 springboot 的 iot 项目( 10 多个服务) 改造成 native ,累个半死,32c256g 机器 gradle 不开多线程要编 50 多分钟,开了也要 18 分钟
|
99
someonedeng 315 天前
这个锅应该 spring 来接,或者其实不该接。
内存敏感就不该选 spring 呢? vertx 、直接 netty 都能搞,或者写写 go :doge |
100
chengxiao 315 天前
有个问题啊, 没写过 java,无意间刷抖音刷到个视频
说写 spring 用 mybatis orm 想输出 执行的 sql 语句,需要装一个 IDE 插件.....这东西配不出来么???还需要借助 IDE 才能实现?? |