[关闭]
@946898963 2018-05-18T12:16:40.000000Z 字数 3301 阅读 1390

Volley-ByteArrayPool

Android控件跟框架 Android源码分析


Volley在对响应的实体进行操作的时候,使用到了byte[],由于volley是轻量级频次高的网络请求框架,因此会大量使用到byte[],这样的话会频繁创建和销毁byte[]。为了提高性能,volley定义了一个byte[]缓冲池,即ByteArrayPool。

更详细的说,由于Volley的目的是同时出现高并发的请求,并且很快结束。如果通过普通的方式一次性创建大量的请求对象,然后等待GC,有可能造成内存抖动.Volley认为权衡的方法是使用固定大小的内存,专门用于创建请求,虽然提高了内存占用,但这种占用是持久的,不会引起重复的占用,也不会引起大量的GC占用时间,所以创建了ByteArrayPool专门用于此目的。

默认使用容量为4K的ByteArrayPool作为请求内存空间。

在ByteArrayPool 内,定义了两个集合,分别是存储按大小顺序排列byte[]的list和按使用先后顺序排列byte[]的list。在volley中所需要使用到的byte[]从该缓冲池中来取,当byte[]使用完毕后再归还到该缓冲池,从而避免频繁的创建和销毁byte[],在缓存池满了的时候删除该集合中的最前面元素,直到缓存池有空闲为止。。

  1. /**
  2. * 字节数组缓冲池:
  3. *
  4. * byte[] 的回收池,用于 byte[] 的回收再利用,减少了内存的分配和回收。主要通过一个元素长度从小到大排序的ArrayList作为 byte[] 的缓存,另有一个按使用时间先后排序的ArrayList属性用于缓存满时清理元素。
  5. */
  6. public class ByteArrayPool {
  7. /** The buffer pool, arranged by last use 按使用的先后时间顺序排序*/
  8. private List<byte[]> mBuffersByLastUse = new LinkedList<byte[]>();
  9. /** The buffer pool, arranged by buffer size 按大小顺序排序*/
  10. private List<byte[]> mBuffersBySize = new ArrayList<byte[]>(64);
  11. /** The total size of the buffers in the pool 池中所有byte[]的长度之和 */
  12. private int mCurrentSize = 0;
  13. /**
  14. * 池中单个byte[]的最大长度
  15. * The maximum aggregate size of the buffers in the pool. Old buffers are discarded to stay
  16. * under this limit.
  17. */
  18. private final int mSizeLimit;
  19. /** Compares buffers by size 比较器,用于排序,按byte[]的字节长度进行排序*/
  20. protected static final Comparator<byte[]> BUF_COMPARATOR = new Comparator<byte[]>() {
  21. @Override
  22. public int compare(byte[] lhs, byte[] rhs) {
  23. return lhs.length - rhs.length;
  24. }
  25. };
  26. /**
  27. * 创建byte[]缓冲池,并设定池中单个byte[]的最大长度
  28. * @param sizeLimit the maximum size of the pool, in bytes
  29. */
  30. public ByteArrayPool(int sizeLimit) {
  31. mSizeLimit = sizeLimit;
  32. }
  33. /**
  34. * 从池中获取一个可用的byte[],如果没有,就创建一个。参数为想要获取多大长度的byte[]
  35. * Returns a buffer from the pool if one is available in the requested size, or allocates a new
  36. * one if a pooled one is not available.
  37. *
  38. * @param len the minimum size, in bytes, of the requested buffer. The returned buffer may be
  39. * larger.
  40. * @return a byte[] buffer is always returned.
  41. */
  42. public synchronized byte[] getBuf(int len) {
  43. //遍历按长度排序的池
  44. for (int i = 0; i < mBuffersBySize.size(); i++) {
  45. byte[] buf = mBuffersBySize.get(i);
  46. //如果当前的byte[]的长度大于给定的长度,就返回该byte[]
  47. if (buf.length >= len) {
  48. //池中所有byte[]的长度之和减去返回出去的byte[]的长度
  49. mCurrentSize -= buf.length;
  50. //从按顺序排列的池中移除该byte[]
  51. mBuffersBySize.remove(i);
  52. //从按使用顺序排列的池中移除该byte[]表示该byte[]正在使用中,其他不能再使用该byte[]
  53. mBuffersByLastUse.remove(buf);
  54. return buf;
  55. }
  56. }
  57. //创建一个新的byte[]
  58. return new byte[len];
  59. }
  60. /**
  61. * Returns a buffer to the pool, throwing away old buffers if the pool would exceed its allotted
  62. * size.
  63. * 当使用完一个byte[]后,将该byte[]返回到池中
  64. * @param buf the buffer to return to the pool.
  65. */
  66. public synchronized void returnBuf(byte[] buf) {
  67. //如果为空或者超过了设定的单个byte[]的最大长度 那么就不再池中保存该byte[]
  68. if (buf == null || buf.length > mSizeLimit) {
  69. return;
  70. }
  71. //在按使用时间顺序排序的池中添加该byte[]
  72. mBuffersByLastUse.add(buf);
  73. //利用二分查找法,找出在按大小排序的池中该byte[]应该存放的位置
  74. int pos = Collections.binarySearch(mBuffersBySize, buf, BUF_COMPARATOR);
  75. //如果找不到,则返回-1
  76. if (pos < 0) {
  77. //当找不到时,也就是在0位置添加
  78. pos = -pos - 1;
  79. }
  80. mBuffersBySize.add(pos, buf);
  81. //增加最大长度
  82. mCurrentSize += buf.length;
  83. //清理,不能超过字节总数最大值
  84. trim();
  85. }
  86. /**
  87. * Removes buffers from the pool until it is under its size limit.
  88. */
  89. private synchronized void trim() {
  90. //当现有字节总数超过了设定的界限,那么需要清理
  91. while (mCurrentSize > mSizeLimit) {
  92. //按照使用的先后顺序来倾全力,最新使用的最先被清除
  93. byte[] buf = mBuffersByLastUse.remove(0);
  94. //同样在该池中也清除
  95. mBuffersBySize.remove(buf);
  96. //减小现有字节最大长度
  97. mCurrentSize -= buf.length;
  98. }
  99. }
  100. }

其实其主要思路就是:将最新使用的放在mBuffersByLastUse的最后面,这样回收的就最晚。而且LruCache的实现思路也和这个完全一样,建议阅读LruCache源码解析

参考链接:

Android中的volley_5_字节数组缓冲池ByteArrayPool 和使用缓冲池技术的自定义的PoolingByteArrayOutputStream
Volley之ByteArrayPool——LruCache实现
vooley源码之ByteArrayPool

Java基础之集合框架--Collections.binarySearch()

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注