1
bunnyblueair 6 天前
ProGuard
|
2
4ra1n OP ProGuard 主要是两个问题,第一个配置非常麻烦,不是容易上手的方式
另外一个问题是,它应该是静态分析的引用关系,而不是动态决定的,比如反射问题,某些功能如果是运行时候决定是否调用某个类的,是无法处理的 |
3
foolishcrab 5 天前
可行,不需要考虑对应用性能影响的时候这个是很简单的东西。
叫 reachability analysis, native image 就有一个专门的 agent 来收集 runtime reflection metadata 之类的东西。 其实这个方案最大的问题在于你帖子里的第二步,对于一个大型软件而言这是很难的,所以一般要在生产上挂着用真实流量收集,这样的话就需要考虑 agent 的性能影响。这里就不展开了 |
4
sagaxu 5 天前
java --verbose:class 找出用到的所有 class 和 jar 包,删掉没用的 jar 包,甚至 jar 包内部删掉无用的 class
|
5
chendy 5 天前
fat jat 解压开,依赖的 jar 包放某个共享目录
所有项目挂在这个共享目录,然后配好 classpath 比较丑陋,但是确实能用 |
6
4ra1n OP 已经实现了,大概是:
capabilities.can_generate_all_class_hook_events = 1; (*jvmti)->AddCapabilities(jvmti, &capabilities); callbacks.ClassFileLoadHook = &ClassLoadHook; 在 ClassLoadHook 函数中做收集 java 启动参数 -agentpath:/path/to/agent.dll 可以收集所有加载的 class 信息,动态地 |
7
4ra1n OP 我发现不能对 ClassFile 做操作,有时候取到的 name 是 null
callbacks.ClassFileLoadHook = &ClassLoadHook; 使用 ClassLoad 会更靠谱 callbacks.ClassLoad = &ClassLoadHook; void JNICALL ClassLoadHook( jvmtiEnv *jvmti_env, JNIEnv *jni_env, jthread thread, const jclass klass) { char *classSignature; char *genericPtr; const jvmtiError err = (*jvmti_env)->GetClassSignature( jvmti_env, klass, &classSignature, &genericPtr); if (err != JVMTI_ERROR_NONE) { LOG_JVM(jni_env,"ERROR GET CLASS SIGNATURE"); return; } DoAnalyze(jni_env,classSignature); (*jvmti_env)->Deallocate(jvmti_env, (unsigned char *) classSignature); if (genericPtr != NULL) { (*jvmti_env)->Deallocate(jvmti_env, (unsigned char *) genericPtr); } } |
8
635925926 3 天前
代码里搜索依赖包的基础包名如何。依赖使用不多的就改成自己实现。
|
9
lixiaolin123 3 天前
@4ra1n java agent 不是可以通过字节码/字节注入来实现运行时的吗?
|
10
Aresxue 2 天前
这个诉求没这么复杂,java agent 把 instrumentation 的引用保存起来就行了,然后放线上去接受真实流量,跑个一天或者手动触发业务操作,再把某台容器从注册中心剔除掉,到这台容器上调用 http 接口,接口里面用 java.lang.instrument.Instrumentation#getAllLoadedClasses 获取所有的 class ,然后对 class 所在 jar 包去重就行了
|
11
lianhuayu420 2 天前
记得 maven 好像有个插件可以将所有只用到的 class 抽出来然后打包
|
12
4ra1n OP @lianhuayu420 嗯,这个主要问题是,运行时到底加载了哪些 CLASS
maven 插件的静态分析难免漏了 例如一个 controller 接收 param clazz=xxx 代码是 Class.forname(xxx); 然后 newInstance 后续做什么事情 如果不动态地根据功能测出具体业务需要哪个 class 就会导致不可用 我的出发点是这个 |
13
4ra1n OP @Aresxue 感谢
确实 Java 层做信息收集,比 C 层 callbacks.ClassLoad 会更通用,我之后实践一下 两者的区别是: C 层的 Hook 是实时的,Java Agent 是做完一些列操作之后,调用一下 getAllLoadedClasses 得到这个过程中的结果 就这个需求来看,不太需要实时地,最终拿到结果即可 |
14
int0x03 1 天前
如果是在程序稳定一段时间后查看所有被加载的类, 可以尝试下面的方法:
```bash # 找到对应的 Java 进程 $ xxx/jdk/bin/jps 77675 MyApp # 查看 jcmd 子命令, 根据 JDK 版本, 可能看到不同的子命令 $ xxx/jdk/bin/jcmd 77675 help GC.class_histogram VM.class_hierarchy VM.classes # 查看加载的类 $ xxx/jdk/bin/jcmd 77675 GC.class_histogram 77675: num #instances #bytes class name (module) ------------------------------------------------------- 1: 2680074 131859776 [B ([email protected]) 2: 2566521 61596504 java.lang.String ([email protected]) 3: 1194171 47766840 java.util.TreeMap$Entry ([email protected]) 4: 348145 29392240 [Ljava.lang.Object; ([email protected]) 5: 139184 19783688 [I ([email protected]) 6: 59540 18054840 [J ([email protected]) 7: 322735 10327520 java.util.HashMap$Node ([email protected]) # 或者上面的结果保存到 csv, 然后做数据处理 ``` |