uniquetruth / remote-debug-agent

a useful java agent for integration testing
Apache License 2.0
71 stars 25 forks source link

调用链数据过大,序列化的时候不会出现栈溢出吗? #6

Closed yang-yao closed 2 years ago

yang-yao commented 2 years ago

公司会封装一些三方包,封装后包名前缀跟项目包名前缀一样,这个也不好通过exclude排除,这样的话三方包参与调用链,序列化的时候感觉会出现栈溢出

uniquetruth commented 2 years ago

includes和excludes其实可以理解为黑白名单,我的设计思路应该是能处理大部分情况的,我实在想象不出来你所说的即不好通过includes指定,也不好通过excludes排除的情况是什么。能否给个具体的例子?
我不太清楚你所说的栈溢出具体是什么意思?如果是指的调用链长度问题的话,该链是一个先进先出的有限长度队列,其长度用traceMax指定,可以看wiki中的参数手册。目前如果记录的方法过多的话,trace/list接口可能会出问题(json格式的输出会报错,原先我还做了一个纯文本格式的输出,但是后来被我废弃了,总之目前建议按需配置限额,不要让队列被占满)。

yang-yao commented 2 years ago

比如 公司业务代码在包 com.xxx. 下 公司封装的三方包的包名前缀是 com.xxx.zk. 或者 com.xxx.dubbo. 等等 有很多 这种情况下 注入的时候就要这样写 includes = com.xxx. excludes=com.xxx.zk.:com.xxx.dubbo. 问题在于三方包有很多,那么excludes就要写很多,这样看起来也不太灵活 如果不排除方包的话,调用链将非常大

uniquetruth commented 2 years ago

你可以使用正则表达式excludes=com.xxx.(zk)|(dubbo),将所有第三方包放到一个表达式中,这样会使配置短一些。如果第三方包数量多于com.xxx下自己的软件包的话,可以把这种方式应用到includes参数中。正则表达式的功能很强大,多研究一下应该可以应付这种情况。

yang-yao commented 2 years ago

关于栈溢出是这样的 比如下面的调用链返回

            {
                "coverage": "[133,148]",
                "cost time": 0,
                "method": "java.lang.String org.chg.coverage.domain.ProjectInfo.toString()",
                "calls": [
                    {
                        "coverage": "[117,128]",
                        "cost time": 0,
                        "method": "int org.chg.coverage.domain.ProjectInfo.hashCode()",
                        "calls": [
                            {
                                "coverage": "[22,22]",
                                "cost time": 0,
                                "method": "java.lang.Long org.chg.coverage.domain.ProjectInfo.getId()",
                                "return value": "0",
                                "sql": []
                            },

calls子调用如果层级过多的话,通过下面的 json序列化应该会栈溢出,具体多少层级没测试,但应该会溢出

List<HashMap<String, Object>> result = prepareGeneralObject(l, displayTime, sql, snapshot);
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
return gson.toJson(result);

目前 您是通过 traceMax来限制调用方法的数量,默认为65535,达到上限后会从先记录的方法开始删除 这样的话,调用链不是不完整了吗,如果通过这个调用链来计算覆盖率的话,是不是覆盖率就不准确了

uniquetruth commented 2 years ago

你说的是Gson的问题了,其算法会不会有栈溢出风险,我们只能相信google的程序员了。另外jvm的栈高限制是可以通过参数调节的,就像我的traceMax参数一样,主要的设计目的是为了保护内存,如果你的内存很大的话,完全可以调节这些值以适应自己的需要。 trace/list等接口的定位是测试、调试用接口,设计目的是用来看一个非常具体的操作所运行的代码。关注覆盖率的话还是建议使用落盘生成的cover file。

uniquetruth commented 2 years ago

我明白你的意思了,你是说prepareGeneralObject方法递归调用自身,深度过多可能栈溢出是吧? 这是不用担心的,或者说你应该担心的不是我工具内的代码。因为prepareGeneralObject方法递归调用的次数肯定小于等于所监控的业务代码的方法栈高度,也就是说如果你的业务代码不会造成栈溢出,那么这里也不会。所以你只用关心你的业务代码会不会造成栈溢出就可以了。

yang-yao commented 2 years ago

prepareGeneralObject方法递归调用不溢出, 那么接着进行的序列化 gson.toJson(result); 也不会溢出? gson不是太懂 , 我是担心序列化的时候溢出

uniquetruth commented 2 years ago

据我所知,gson.toJson造成栈溢出只有一种情况,那就是作为入参的对象出现循环引用,比如入参为A,A的字段b指向了对象B,B的字段a又指向了A。这跟参数的结构有关,与参数的大小(长度)无关。在本工具的代码中,不存在这样的情况。

yang-yao commented 2 years ago

我准备把这个接入到我们测试环境的项目试试 看看是否有栈溢出的问题