We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
已经找到原因以及解决办法(由于个人fork 了此项目一份代码,并且改动很大,源码已经和 LogUtils 库不同了。所以不好修改,待我有空会提交并关闭此问题) 提出此问题望作者修复 谢谢。
// 先创建一个 map 和 message // 注意,map 和 message 都有 Parser 实现 // 分别对应 MapParse 和 MessageParse Map<String, Object> testMap = new HashMap<>(); Message message = Message.obtain(); // 在这里,map 持有 message, 而 message 持有 map message.obj = testMap; testMap.put("testKey", message); LogUtil.objToString(testMap);
其中 LogUtil.objToString 方法是我调试用的方法 它实际是这样的
LogUtil.objToString
public static String objToString(Object object) { return ObjectUtil.getInstance().objectToString(object); }
也就是说,ObjectUtil 的 objectToString 方法内部实现有一点小错误
原因就是循环引用后,解析的时候,循环解析了。 虽然平常确实不会有这种情况,但是实际确实遇到了
viewModel?.helloWorld?.observe(this, Observer { // LogUtil.objToString() 默认情况下,解析 ObservableField 会死循环 logger.i("listener on changed" + com.zhouzhou.newsdemo.LogUtil.objToString(it)) })
以上面代码为例
当检测到 Object 是一个 Map 的时候,调用了 MapParse.parseString 方法 然后 MapParse 中 又调用了 ObjectUtil.getInstance().objectToString(value) 来解析 value 而此 value 就是 Message,而 Message 中又引用了 Map,这时候又去解析 Map。不断的循环
MapParse.parseString
MapParse
ObjectUtil.getInstance().objectToString(value)
value
Message
Map
然后......就炸了
在 ObjectUtil 类中,解析 Object 对象时,传递了 childLevel 层级。 所以,对 Object 对象的循环引用不会导致死循环。 但是对继承Parser的解析类,没有传递 childLevel 层级,导致解析时死循环
解决办法应该是:将 Parser 接口方法 String parseString(T t); 增加一个参数,childLevel 层级 在 Parser 实现类中,调用 ObjectUtil.getInstance().objectToString 方法时,将 childLevel 层级始终传递并 +1,使其可以被跳出,防止死循环了
ObjectUtil.getInstance().objectToString
package com.apkfuns.logutils 中的 Logger
Logger
方法 getTopStackInfo 调用了两次 getCurrentStackTrace
getTopStackInfo
getCurrentStackTrace
private String getTopStackInfo() { String customTag = mLogConfig.getFormatTag(getCurrentStackTrace()); if (customTag != null) { return customTag; } StackTraceElement caller = getCurrentStackTrace(); String stackTrace = caller.toString(); stackTrace = stackTrace.substring(stackTrace.lastIndexOf('('), stackTrace.length()); String tag = "%s.%s%s"; String callerClazzName = caller.getClassName(); callerClazzName = callerClazzName.substring(callerClazzName.lastIndexOf(".") + 1); tag = String.format(tag, callerClazzName, caller.getMethodName(), stackTrace); return tag; }
建议改成只调用一次 getCurrentStackTrace 因为 Thread.currentThread().getStackTrace() 方法是一个相对耗时操作。 之前测试过 性能。改成只调用一次之后,性能提升大约 百分之70 大概就是 一万条日志从 400ms 减少到 两百多ms
Thread.currentThread().getStackTrace()
private String getTopStackInfo() { StackTraceElement caller = getCurrentStackTrace(); if (caller == null) return "Null Stack Trace"; String stackTrace = caller.toString(); stackTrace = stackTrace.substring(stackTrace.lastIndexOf('(')); String tag = "%s.%s%s"; String callerClazzName = caller.getClassName(); callerClazzName = callerClazzName.substring(callerClazzName.lastIndexOf(".") + 1); tag = String.format(tag, callerClazzName, caller.getMethodName(), stackTrace); return tag; } private StackTraceElement getCurrentStackTrace() { StackTraceElement[] trace = Thread.currentThread().getStackTrace(); int stackOffset = getStackOffset(trace); return stackOffset == -1 ? null : trace[stackOffset]; } private int getStackOffset(StackTraceElement[] trace) { for (int i = tackOffset; i < trace.length; i++) { if (trace[i].getClassName().equals(findTackClassName)) return ++i; } return -1; }
The text was updated successfully, but these errors were encountered:
修改后的打印日志:
I/LogUtils: java.util.HashMap [ testKey -> android.os.Message [ what = 0 when = 0 arg1 = 0 arg2 = 0 data = android.os.Bundle [ ] obj = java.util.HashMap [ testKey -> { when=-19d7h52m44s765ms barrier=0 } ] ] ]
已经没有循环解析导致的问题了,最后的
testKey -> { when=-19d7h52m44s765ms barrier=0 }
已经跳出了解析。
Sorry, something went wrong.
棒棒棒!! 最近工作比较忙,周末会抽空看看的,感谢反馈
另外。Log4a 日志文件写入库,cpp 文件我提交过 bug 修复,Log4a 已经合并到 主分支了
pqpo/Log4a@6942b7a
建议您也从 Log4a 重新同步一下 cpp 文件
No branches or pull requests
已经找到原因以及解决办法(由于个人fork 了此项目一份代码,并且改动很大,源码已经和 LogUtils 库不同了。所以不好修改,待我有空会提交并关闭此问题)
提出此问题望作者修复
谢谢。
复现代码
其中
LogUtil.objToString
方法是我调试用的方法它实际是这样的
分析及解决
原因就是循环引用后,解析的时候,循环解析了。
虽然平常确实不会有这种情况,但是实际确实遇到了
分析:
以上面代码为例
当检测到 Object 是一个 Map 的时候,调用了
MapParse.parseString
方法然后
MapParse
中 又调用了ObjectUtil.getInstance().objectToString(value)
来解析 value而此
value
就是Message
,而 Message 中又引用了Map
,这时候又去解析 Map。不断的循环然后......就炸了
解决
在 ObjectUtil 类中,解析 Object 对象时,传递了 childLevel 层级。
所以,对 Object 对象的循环引用不会导致死循环。
但是对继承Parser的解析类,没有传递 childLevel 层级,导致解析时死循环
解决办法应该是:将 Parser 接口方法 String parseString(T t); 增加一个参数,childLevel 层级
在 Parser 实现类中,调用
ObjectUtil.getInstance().objectToString
方法时,将 childLevel 层级始终传递并 +1,使其可以被跳出,防止死循环了不与此 bug 有关的一点优化建议
package com.apkfuns.logutils 中的
Logger
方法
getTopStackInfo
调用了两次getCurrentStackTrace
建议改成只调用一次
getCurrentStackTrace
因为
Thread.currentThread().getStackTrace()
方法是一个相对耗时操作。之前测试过 性能。改成只调用一次之后,性能提升大约 百分之70
大概就是 一万条日志从 400ms 减少到 两百多ms
The text was updated successfully, but these errors were encountered: