按照专家的建议,为了改善内存的使用,以及程序的优良性,建议引入对象池技术,以最大程度改善程序性能,个人看了相关资料,主要有两方面的有点,
优点一:不需要VM反复为"同一个对象"去创建,同时也不需要,也就是不会引入新的内存空间,占用新的内存地址;
优点二:由于一些对象创建了以后,不就又被释放了,如果再使用的话,就需要重新创建新的对象,这样重新创建需要消耗更多的时间.
专家的建议:
大多数对象的复用,最终实施的方案都是利用对象池技术,要么是在编写代码的时候显式的在程序里面去创建对象池,然后处理好复用的实现逻辑,要么就是利用系统框架既有的某些复用特性达到减少对象的重复创建,从而减少内存的分配与回收,原理示意图如下:
:
这个图第一次俺也没看懂,后来根据自己做的程序,大致的意思如下:绿色方块标记为A,中间灰色方块标记为B,最右边是模块C:
A : 对象池,保存了必要的对象,绿色箭头代表对象池提供已经保存的对象给程序访问;
B : 程序段,灰色往左的箭头是程序去到对象池要对象的
C : 内存消耗,往左的箭头是新开辟内存;
注意两个地方就好了:
第一个地方:绿色箭头出现的时候,即程序向对象池要对象,对象池提供了必要的对象,但是这个时候发现B侧右边是没有箭头的,说明这个过程不会在Memory heap中开闭新的内存,即不会再增加新的内存消耗.
第二个地方:B方块右方下侧有两个箭头(不是色盲啊,就当做蓝色吧,不知道叫什么名的颜色),这两根箭头说明在操作对象池的时候,会消耗一部分因为程序运行导致的内存消耗,虽然很少,那么意味着什么呢?意味着开发者保存到对象池的对象一定要足够"重",如果随便保存一个简单类型的到对象池,可能访问对象池需要消耗的内存比节省下来的还要多,得不偿失.
下面给出一个网上的测试demo,但是网上面的似乎有点错误,我改了一下:
<1> : 新建一个android 工程:
<2> 具体代码如下:
DurianMainActivity.java
package org.durian.durianobjectpool;
import org.apache.commons.pool.BasePoolableObjectFactory;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.impl.StackObjectPool;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import org.durian.durianobjectpool.bean.DurianUser;
import org.durian.durianobjectpool.pool.DurianObjectPool;
public class DurianMainActivity extends ActionBarActivity implements View.OnClickListener{
private Button mButton;
private Button mLibButton;
private Button mGc;
private DurianObjectPool objPool ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.durian_main);
mButton=(Button)findViewById(R.id.button);
mButton.setOnClickListener(this);
mLibButton=(Button)findViewById(R.id.libbutton);
mLibButton.setOnClickListener(this);
mGc=(Button)findViewById(R.id.gc);
mGc.setOnClickListener(this);
objPool = new DurianObjectPool();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_durian_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onClick(View v) {
int id=v.getId();
switch(id){
case R.id.button:
new Thread(new Runnable() {
@Override
public void run() {
//这里面的Object可以换成任意的对象,
//建议是重量级的对象
objPool.createPool();
Object obj = objPool.getObject();
DurianUser user=(DurianUser)objPool.getObject();
user.setName("zhibao.liu");
user.setOld(10000);
objPool.returnObjection(user);
objPool.closeObjectPool();
}
}).start();
break;
case R.id.libbutton:
ObjectPool pool = new StackObjectPool(new UserFactory());
User u = null; // 从池中借出一个对象
try {
u = (User) pool.borrowObject();
} catch (Exception e) {
e.printStackTrace();
}
u.setName("me");
u.sayHello();
try {
pool.returnObject(u); // 归还对象
} catch (Exception e) {
e.printStackTrace();
}
break;
default:
break;
}
}
static class UserFactory extends BasePoolableObjectFactory {
/**
* 产生一个新对象
*/
public Object makeObject() {
return new User();
}
/**
* 还原对象状态
*/
public void passivateObject(Object obj) {
User u = (User) obj;
u.clear();
}
}
static class User {
String name;
void setName(String name) {
this.name = name;
}
void sayHello() {
System.out.println("hello, " + name);
}
void clear() {
name = "";
}
}
}
DurianObjectPool.java
package org.durian.durianobjectpool.pool;
import org.durian.durianobjectpool.bean.DurianUser;
import java.util.Enumeration;
import java.util.Objects;
import java.util.Vector;
/**
* Project name : DurianObjectPool
* Created by zhibao.liu on 2016/1/8.
* Time : 16:06
* Email warden_sprite@foxmail.com
* Action : durian
*/
public class DurianObjectPool {
//预计对象池的大小
private int mNumObjects = 10;
//预计对象池最大数量
private int mMaxObjects = 50;
//存放对象池中对象的向量(PoolObject类型)
private Vector objects = null;
//创建一个对象池
public synchronized void createPool() {
//确保对象池没有创建,如果创建好了,就直接返回
if (objects != null) {
return;
}
//创建保存对象的向量,初始化时有0个元素
objects = new Vector();
//根据mNumObjects中设置的值,循环创建指定数目对象
for (int x = 0; x < mNumObjects; x++) {
if ((objects.size() == 0) && this.objects.size() < this.mMaxObjects) {
// Object obj = new Object();
DurianUser obj=new DurianUser();
objects.addElement(new PooledObject(obj));
}
}
}
public synchronized Object getObject() {
//确保对象池已经被创建
if (objects == null) {
return null;//对象池还没有创建
}
//获得一个可用对象
Object conn = getFreeObject();
//如果目前没有可以使用对象,即所有的对象都在使用
while (conn == null) {
wait(250);
//重新再试,直到获得可用的对象
conn = getFreeObject();
}
//返回可用的
return conn;
}
/**
* 本函数从对象池对象 objects 中返回一个可用的的对象,如果
* 当前没有可用的对象,则创建几个对象,并放入对象池中。
* 如果创建后,所有的对象都在使用中,则返回 null
*/
private Object getFreeObject() {
// 从对象池中获得一个可用的对象
Object obj = findFreeObject();
if (obj == null) {
//这个地方是向对象池增加一个新的对象
//网上面的这句话有问题,似乎不正确
createObjects();
//重新从池中查找是否可用的对象
obj = findFreeObject();
// 如果创建对象后仍获得不到可用的对象,则返回 null
if (obj == null) {
return null;
}
}
return obj;
}
private void createObjects(){
// Object obj = new Object();
DurianUser obj=new DurianUser();
objects.addElement(new PooledObject(obj));
mNumObjects++;
}
/**
* 查找对象池中所有的对象,查找一个可用的对象,
* 如果没有可用的对象,返回 null
*/
public Object findFreeObject() {
Object obj = null;
PooledObject pObj = null;
// 获得对象池向量中所有的对象
Enumeration enumeration = objects.elements();
// 遍历所有的对象,看是否有可用的对象
while (enumeration.hasMoreElements()) {
pObj = (PooledObject) enumeration.nextElement();
// 如果此对象不忙,则获得它的对象并把它设为忙
if (!pObj.isBusy()) {
obj = pObj.getObjection();
pObj.setBusy(true);
}
}
return obj;
}
/**
* 此函数返回一个对象到对象池中,并把此对象置为空闲。
* 所有使用对象池获得的对象均应在不使用此对象时返回它。
*/
public void returnObjection(Object obj) {
if (objects == null) {
return;
}
PooledObject pObj = null;
Enumeration enumeration = objects.elements();
// 遍历对象池中的所有对象,找到这个要返回的对象对象
while (enumeration.hasMoreElements()) {
pObj = (PooledObject) enumeration.nextElement();
// 先找到对象池中的要返回的对象对象
if (obj == pObj.getObjection()) {
pObj.setBusy(false);
break;
}
}
}
/**
* 关闭对象池中所有的对象,并清空对象池。
*/
public synchronized void closeObjectPool() {
if (objects == null) {
return;
}
PooledObject pObj = null;
Enumeration enumeration = objects.elements();
while (enumeration.hasMoreElements()) {
pObj = (PooledObject) enumeration.nextElement();
if (pObj.isBusy()) {
wait(5000);
}
objects.removeElement(pObj);
}
objects = null;
}
private void wait(int seconds) {
try {
Thread.sleep(seconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 内部使用的用于保存对象池中对象的类。
* 此类中有两个成员,一个是对象,另一个是指示此对象是否正在使用的标志 。
*/
class PooledObject {
Object objection = null;
boolean busy = false;
public PooledObject(Object objection) {
this.objection = objection;
}
public Object getObjection() {
return objection;
}
public void setObjection(Object objection) {
this.objection = objection;
}
public boolean isBusy() {
return busy;
}
public void setBusy(boolean busy) {
this.busy = busy;
}
}
}
DurianUser.java
package org.durian.durianobjectpool.bean;
/**
* Project name : DurianObjectPool
* Created by zhibao.liu on 2016/1/8.
* Time : 18:00
* Email warden_sprite@foxmail.com
* Action : durian
*/
public class DurianUser {
private String name;
private int old;
public void setName(String name){
this.name=name;
}
public String getName(){
return name;
}
public void setOld(int old){
this.old=old;
}
public int getOld(){
return this.old;
}
}
布局如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/button"
android:text="button"
android:layout_width="250dp"
android:layout_height="100dp" />
<Button
android:id="@+id/libbutton"
android:text="lib pool"
android:layout_width="250dp"
android:layout_height="100dp" />
<Button
android:id="@+id/gc"
android:text="gc"
android:layout_width="250dp"
android:layout_height="100dp" />
</LinearLayout>
上面工程记得添加commons-pool-1.5.6.jar,如果有公司不建议添加jar包,这个jar是开源的有代码,可以借鉴里面的source code放到自己工程中.
jar下载地址 : http://www.java2s.com/Code/Jar/c/Downloadcommonspool16sourcesjar.htm
<3> : 运行结果即可,单开Android studio Monitor ,上面的例子不是什么大对象,不会造成太大性能改善,参考学习之用.