ppm内存溢出问题解决

本文详细记录了一次解决PPM系统内存溢出问题的过程,从JVM参数调优、堆栈分析、Native Heap排查到分布式事务的影响,最终发现是由于使用了特定的Oracle XA数据库驱动导致的问题,通过更换驱动并调整事务处理方式成功解决。

ppm内存溢出问题解决

一、发现问题

PPM系统手工下发数据到CRM时。下发10万条,每次2000条分页下发。

时间长了会出现内存溢出。在测试库测试发现,linux的内存占用会上升到40%,然后weblogic抛出错误

 

# java.lang.OutOfMemoryError: requested 67 bytes for char in /BUILD_AREA/jdk6_05/hotspot/src/share/vm/runtime/sharedRuntime.cpp. Out of swap space?

另外,在weblogictomcat下面测试,weblogic下面会出现这个问题,tomcat没有问题。另外把这句代码注释后,问题就不会出现了。Weblogictomcat的不同点在于weblogic用了分布式事务,tomcat是开发环境,没有用分布式事务。

 

二、分析问题

1、JVM参数调优

问题一定是和这个查询语句有关。但是这个SQL查询没有问题,dao也是单例的,对象也是方法内定义的,也不是静态的,应该会被回收:

 

看了weblogic的启动配置,于是通过打印GC来看一下问题,一开始发现打印的GC是这种格式:

352.403: [GC 352.404: [DefNew: 13487K->737K(14208K), 0.0121280 secs] 84892K->72466K(203264K), 0.0122890 secs] [Times: user=0.01 sys=0.01, real=0.01 secs] 

DefNew代表的意义是串行回收器,而这个应用是大吞吐量的应用,应该是并行回收才对。所以就改成了并行回收。

关于GC日志:http://blog.youkuaiyun.com/huangzhaoyang2009/article/details/11860757

关于Jvm内存调优jstat的使用:

http://www.cnblogs.com/jackyrong/archive/2010/01/21/1653163.html

新生代与老生代:http://blog.youkuaiyun.com/ustcxjt/article/details/7287430

详细的JVM内存模型、GC收集器:

<think>好的,我现在需要分析用户的问题:在Keil5中使用C语言编程时,LCD显示屏先显示't 13.ppm',然后才显示'13ppm'。用户想知道原因。我需要结合之前的回答和提供的引用内容来找出可能的原因。 首先,回顾用户提供的代码和相关引用。在引用[1]中,有一个displayData函数,它会定期读取传感器数据并刷新LCD。可能的流程是,每次调用显示函数时,先清屏再显示新内容。如果显示过程中有短暂显示旧数据或中间状态,可能是因为清屏的位置不对,或者在更新显示内容时有延迟。 另外,用户之前的问题涉及浮点数转整数和Keil配置,可能相关的数学运算或类型转换问题也可能导致显示异常。但当前问题更可能涉及显示逻辑或字符串处理。 查看引用[5]提到的sprintf函数的使用,如果用户使用类似的方法格式化字符串,可能在构造字符串时出现了临时字符,比如在生成数值时,未正确初始化或格式字符串有误,导致中间结果短暂显示。例如,在格式化字符串时,可能错误地包含了多余的字符,如't',或者在更新显示时,未完全覆盖之前的字符。 另一个可能性是LCD的刷新机制。比如,在清屏(LCD_Clear)之后,如果在写入新内容之前有延迟,或者LCD模块本身在清屏到显示新内容之间有残留图像,可能会短暂显示旧内容。但根据引用[1]中的代码,LCD_Clear()是在显示数据之前调用的,所以应该先清屏再显示。但如果清屏操作需要一定时间,而代码在清屏后立即写入数据,可能LCD模块还未完成清屏,导致部分旧数据残留。 还有一种情况是字符串拼接错误。例如,如果使用sprintf或类似函数生成显示字符串时,格式字符串中有多余字符或者变量顺序错误,导致临时生成带有't'的字符串,之后修正了数据但未正确刷新。例如,错误的格式字符串如"t %d.ppm",之后更改为"%dppm",但由于某些原因,第一次显示时使用了错误的格式。 此外,代码中可能存在多个显示步骤,比如先显示部分信息,再更新另一部分,导致中间状态被看到。例如,先在第一行显示"t 13.ppm",然后在第二行显示其他内容,之后又更新第一行为"13ppm",但LCD刷新频率较高,导致用户看到中间状态。 还需要考虑缓冲区未正确初始化或覆盖的问题。例如,用于存储显示字符串的数组没有正确终止,或者被其他操作修改,导致残留字符出现。 可能的解决方向包括检查字符串格式化部分是否正确,确保清屏和显示操作的顺序及延迟适当,检查是否有多个显示步骤导致中间状态,以及确认LCD驱动函数是否正常工作,没有硬件延迟或刷新问题。 需要结合用户可能的代码结构,比如是否在显示过程中分步骤更新不同区域,或者在处理传感器数据时有条件判断导致部分更新。例如,当数据未准备好时显示占位符(如't'),待数据就绪后更新为实际值,但处理不当导致短暂显示占位符。 总结可能的原因:1. 字符串格式化错误,临时包含't';2. 清屏与显示顺序不当,残留字符;3. 分步骤更新显示内容导致中间状态可见;4. LCD驱动或硬件延迟问题;5. 缓冲区未正确初始化或覆盖。</think>### 分步解析与解决方案 #### **现象分析** 在LCD显示过程中,先出现`t 13.ppm`,随后变为`13ppm`,通常由以下原因导致: 1. **字符串缓冲区未正确初始化**:未清除旧数据残留字符(如`t`)[^5]。 2. **多步骤刷新逻辑**:分阶段更新显示内容导致中间状态可见[^1]。 3. **硬件刷新延迟**:LCD清屏(`LCD_Clear()`)与写入新数据之间的时序问题[^4]。 4. **格式化字符串错误**:在`sprintf`等函数中误加入临时字符(如`t`)[^5]。 --- #### **关键排查步骤** ##### **1. 检查字符串格式化代码** 假设显示代码中使用了类似引用[5]的`sprintf`函数: ```c char buffer[20]; sprintf(buffer, "t %d.ppm", sensorValue); // 错误:包含多余字符't' LCD_Print(buffer); // 后续修正为: sprintf(buffer, "%dppm", sensorValue); // 正确格式 LCD_Print(buffer); ``` **问题定位**: 若代码中存在**临时调试字符(如`t`)未删除**,或格式字符串误写(如多写`t`或`.`),会导致残留字符显示[^5]。 **修复方案**: 统一格式化字符串,删除冗余字符: ```c sprintf(buffer, "%dppm", sensorValue); // 直接生成目标字符串 ``` --- ##### **2. 验证LCD清屏与刷新的时序** 参考引用[1]的显示逻辑: ```c void displayData(void) { LCD_Clear(); // 清屏应在获取数据后、显示前执行 int gasValue = Get_YanwuValue(); LCD_SetCursor(0, 0); LCD_Printf("Gas: %dppm", gasValue); // 直接显示最终内容 } ``` **问题定位**: 若清屏操作(`LCD_Clear()`)在数据生成**之后**执行,或清屏与显示之间存在其他操作(如传感器读取),可能导致残留帧。 **修复方案**: 确保清屏后立即写入新数据,避免插入延迟或计算: ```c void displayGasValue(void) { int gasValue = Get_YanwuValue(); // 先获取数据 LCD_Clear(); // 立即清屏 LCD_SetCursor(0, 0); LCD_Printf("%dppm", gasValue); // 直接输出目标字符串 } ``` --- ##### **3. 排查缓冲区溢出或未初始化** 若使用全局或静态缓冲区: ```c static char buffer[16]; void updateDisplay() { memset(buffer, 0, sizeof(buffer)); // 必须初始化缓冲区 sprintf(buffer, "%dppm", value); LCD_Print(buffer); } ``` **问题定位**: 未初始化缓冲区时,旧数据(如`t 13.ppm`)可能残留在内存中,与新数据拼接导致乱码[^5]。 **修复方案**: - 使用局部变量并初始化为空: ```c char buffer[16] = {0}; // 自动初始化为全0 sprintf(buffer, "%dppm", value); ``` - 或显式清空缓冲区: ```c memset(buffer, '\0', sizeof(buffer)); // 填充结束符 ``` --- ##### **4. 硬件延迟测试(针对LCD模块)** 某些LCD清屏需要耗时操作(如引用[4]中编译后下载的时序问题): ```c void displayGasValue() { LCD_Clear(); // 清屏耗时2ms Delay_ms(1); // 若延时不足,清屏未完成即写入数据 LCD_Print("13ppm"); // 可能导致残影 } ``` **解决方案**: - 查阅LCD手册确认`LCD_Clear()`的最小执行时间,增加适当延迟: ```c LCD_Clear(); Delay_ms(2); // 根据实际模块调整 LCD_Print("13ppm"); ``` --- ### **最终修正代码示例** ```c // 正确流程:获取数据→清屏→格式化字符串→显示 void Display_GasValue(void) { int gasValue = Get_YanwuValue(); // 获取传感器值 char displayBuffer[16] = {0}; // 局部缓冲区初始化 sprintf(displayBuffer, "%dppm", gasValue); // 直接生成目标字符串 LCD_Clear(); // 清屏后立即显示 LCD_SetCursor(0, 0); LCD_Print(displayBuffer); } ``` --- ### 相关问题 1. **如何避免LCD显示时出现乱码或残留字符?** 确保清屏操作在数据准备好后执行,并使用初始化后的缓冲区[^1][^5]。 2. **sprintf格式化字符串时为何要初始化缓冲区?** 未初始化的缓冲区可能包含旧数据,导致拼接错误[^5]。 3. **Keil中如何调试LCD显示时序问题?** 使用逻辑分析仪监测`LCD_Clear()`和`LCD_Print()`的引脚信号延迟[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值