java.lang.OutOfMemoryError: unable to create native thread: possibly out of memory or process/resource limits reached
at java.base/java.lang.Thread.start0(Native Method)
at java.base/java.lang.Thread.start(Thread.java:798)
at me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker.checkBackgroundProcessStarted(WxMessageInMemoryDuplicateChecker.java:81)
at me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker.isDuplicate(WxMessageInMemoryDuplicateChecker.java:89)
at me.chanjar.weixin.mp.api.WxMpMessageRouter.isMsgDuplicated(WxMpMessageRouter.java:257)
at me.chanjar.weixin.mp.api.WxMpMessageRouter.route(WxMpMessageRouter.java:172)
at me.chanjar.weixin.open.api.impl.WxOpenMessageRouter.route(WxOpenMessageRouter.java:24)
at me.chanjar.weixin.open.api.impl.WxOpenMessageRouter.route(WxOpenMessageRouter.java:20)
at cn.devmgr.mall.wechatopen.WechatNotifyController.callback(WechatNotifyController.java:269)
at jdk.internal.reflect.GeneratedMethodAccessor433.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
... ...
Here is the list of approaches, sorted from quickest / most reliable to slowest / hardest:
1. If you have the source of the class, create an exception in the constructor (without actually throwing it). You can simply examine or print it when you need to know when the thread was created.
2. If you don't have the sources, the thread name can be a good hint who created it.
3. If the name hints to a generic service (like java.util.Timer), then you can create a conditional breakpoint in your IDE in the constructor. The condition should be the thread name; the debugger will then stop when someone creates a thread with this name.
4. If you don't have too many threads, set a breakpoint in the constructors of Thread.
5. If you have many threads, attach a debugger to the app and freeze it. Then examine the stack traces.
6. If everything else fails, get the source code for the Java runtime and add logging code in the classes you want to observe, compile a new rt.jar and replace the original one with your version. Don't try this in production, please.
7. If money isn't an issue, you can use dynamic tracing tools like Compuware APM or, if you're on Linux or Solaris, you can try SystemTap and dtrace, respectively.
@GetMapping("/threads") public Map<String, ?> getThreadStackTraces() { logger.trace("getThreadStackTraces"); Map<String, List<Map<String, Object>>> result = new HashMap<>(); Map<String, Map<String, Object>> threadInfoByKey = new HashMap<>(); for (Thread t : Thread.getAllStackTraces().keySet()) { StackTraceElement[] elements = t.getStackTrace(); List<Map<String, Object>> stackList = new ArrayList<>(); StringBuilder builder = new StringBuilder(); int i = 0; for (StackTraceElement ele : elements) { i++; Map<String, Object> map = new HashMap<>(); map.put("className", ele.getClassName()); map.put("methodName", ele.getMethodName()); map.put("lineNum", ele.getLineNumber()); map.put("fileName", ele.getFileName()); map.put("module", ele.getModuleName()); stackList.add(map);
if (i < 30) { builder.append(ele.getClassName()); builder.append(ele.getMethodName()); } } String status = t.getState().toString().toLowerCase(); String key = builder.toString(); Map<String, Object> threadInfo = threadInfoByKey.get(key); if (threadInfo == null) { threadInfo = new HashMap<>(); threadInfo.put("stack", stackList); threadInfoByKey.put(key, threadInfo); List<Map<String, Object>> list = result.get(status); if (list == null) { list = new ArrayList<>(); result.put(status, list); } list.add(threadInfo); } if (threadInfo.containsKey("counter")) { threadInfo.put("counter", (Integer) threadInfo.get("counter") + 1); } else { threadInfo.put("counter", 1); } if (threadInfo.containsKey("names")) { List<String> names = (List<String>) threadInfo.get("names"); names.add(t.getName()); } else { List<String> names = new ArrayList<>(); names.add(t.getName()); threadInfo.put("names", names); } } return result; }