您的位置:首页 > Web前端

StringBuffer使用不当,引起的性能问题

2017-11-22 15:43 302 查看
最近,因为公司让我完善下调试工具的一个功能,需要用到缓冲区进行数据暂存,原先的想法是缓冲区上限设为5M,当数据存满的时候,删除最先加入的数据,再加入新的数据。傻逼逼的我想到的是使用StringBuffer进行临时存储,直接调用了如下方法来设置缓冲区的上限:

private static StringBuffer stringBuffer=new StringBuffer(5442280);


然后直接开始往StringBuffer写数据,发现能够成功写入数据,并且执行完具体操作后,能正常写出到文件,就觉得完成任务了,让测试去测试该项目,(测试没注意测试上限),然后项目就正常上线了。

直到过了几天······,主管找到我,说了句,为什么拿到的文件大于5M,有些甚至到达了30多M?

一句话瞬间把我整懵逼了,马上找原因,分析问题所在。才知道原来StringBuff是并不能设置缓冲区上限的,只能自动通过写闭环的形式来让StringBuffer形成上限。

//这里缓存使用总量约25M,若将缓存数据写入内存时,因为占用io线程,会导致缓冲区使用增值50~60M,所以要处理好数据的使用
StringBuffer stringTempBuffer=new StringBuffer(5442880);
while ((line = reader.readLine()) != null) {
stringTempBuffer().append(line + "\n");
if (stringTempBuffer().length()>5000000)
{
stringBuffer=stringTempBuffer;
//stringTempBuffer.delete(0,400000);
//达到5M上限,删除最初的400K数据
//后续补充,delete并不会重置数组长度,并不能在根源处彻底解决问题
//最好的做法是新建一个临时buffer,来保存
stringTempBuffer=new StringBuffer(5442880);
//原先的stringTempBuffer会由于没有被引用而被GC回收,释放内存
}
}


问题解决!!!

另一解决办法:使用循环队列
4000
来进行闭环存储(推荐使用,能够将缓存控制在20M以内):

/**
* author: 李文烙
* date: 2017/11/29
* @Desc:循环队列工具类
*/

public class CircleQueue{

/**
* 循环队列 (数组)默认大小
*/
private final int DEFAULT_SIZE = 1000;

/**
* (循环队列)数组的容量
*/
public int capacity;

/**
* 数组:保存循环队列的元素
*/
public char[] elementData;

/**
* 队头(先见先出)
*/
public int head = 0;

/**
* 队尾
*/
public int tail = 0;

/**
* 以循环队列 默认大小创建空循环队列
*/
public CircleQueue() {
capacity = DEFAULT_SIZE;
elementData =new char[capacity];
}

/**
* 以指定长度的数组来创建循环队列
*
* @param initSize
*/
public CircleQueue(final int initSize) {
capacity = initSize;
elementData =new char[capacity];
}

/**
* 获取循环队列的大小(包含元素的个数)
*/
public int size() {
if (isEmpty()) {
return 0;
} else if (isFull()) {
return capacity;
} else {
return tail + 1;
}
}

/**
* 插入队尾一个元素
*/
public void add(final char element) {
if (isEmpty()) {
elementData[0] = element;
} else if (isFull()) {
elementData[head] = element;
head++;
tail++;
head = head == capacity ? 0 : head;
tail = tail == capacity ? 0 : tail;
} else {
if(tail<capacity-1){
elementData[tail + 1] = element;
}else{
head=0;
tail=capacity-2;
}
tail++;

}
}

public boolean isEmpty() {
return tail == head && tail == 0 && (String.valueOf(elementData[tail])==null||String.valueOf(elementData[tail]).equals(""));
}

public boolean isFull() {
return head != 0 && head - tail == 1 || head == 0 && tail == capacity - 1;
}

public void clear() {
elementData=new char[capacity];
head = 0;
tail = 0;
}

/**
* @return 取 循环队列里的值(先进的index=0)
*/
public char[] getQueue() {
final char[] elementDataSort =new char[capacity];
final char[] elementDataCopy = elementData.clone();
if (isEmpty()) {
} else if (isFull()) {
int indexMax = capacity;
int indexSort = 0;
for (int i = head; i < indexMax;) {
if (indexSort<capacity&&i<capacity)
{
elementDataSort[indexSort] = elementDataCopy[i];
indexSort++;
i++;
}
if (i == capacity) {
i = 0;
indexMax = head;
}
if (indexSort==capacity){
break;
}
}
} else {
// elementDataSort = elementDataCopy;//用这行代码代替下面的循环,在队列刚满时候会出错
for (int i = 0; i < tail; i++) {
if (tail<=capacity-1)
{
elementDataSort[i] = elementDataCopy[i];
}
}
}
return elementDataSort;
}
}

用法:
DebugApplication mContext=DebugApplication.getInstance();
while ((line = reader.readLine()) != null) {
//读取不为空的情况下,把log存储在临时变量
//                mContext.getCahceBuffer().append(line + "\n");
for (char i:line.toCharArray())
mContext.getCircleQueue().add(i);
mContext.getCircleQueue().add('\n');
}


注:如果不设置缓冲区上限的后果(Android开发):

1.如果进程为系统核心进程,不会被kill,会导致进程占用过多堆栈空间,且不会被系统自动kill来释放空间,导致整体系统速率被严重拖慢,可能会导致死机

2.如果进程为非系统核心进程,同样也会进程占用过多堆栈空间,但是系统会自动kill进程来释放堆栈内存,偶现系统运行卡顿后正常。

3.恶意增长的情况下会引发OOM(out of memory)问题,导致系统崩溃

开发者可以通过

adb shell getprop | grep heap 来获取当前系统的堆栈空间信息

[dalvik.vm.heapgrowthlimit]: [128m]    //受控情况下的极限堆,超过会引起OOM
[dalvik.vm.heapmaxfree]: [8m]
[dalvik.vm.heapminfree]: [512k]
[dalvik.vm.heapsize]: [384m]
[dalvik.vm.heapstartsize]: [8m]
[dalvik.vm.heaptargetutilization]: [0.75]


adb shell dumpsys meminfo packageName来查看当前进程运行的堆栈空间。

Applications Memory Usage (kB):
Uptime: 13677750 Realtime: 13677750


* MEMINFO in pid 12359 [packageName] *

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐