Heap in java

1. Heap definition

The (binary) heap data structure is an array object that can be viewed as a nearly complete binary tree .

 

就是说 堆 是一近乎 完全二叉树 的 结构,堆可以用来排序(称为堆排序 )。

 

2. Relationship between array index and tree’s nodes

A heap can be stored as an array A.

 

堆可以用 数组 来存储。

 

       We simply number the nodes in the heap from top to bottom, numbering the nodes on each level from left to right and store the ith node in the ith location of the array. (of course remembering that array indexing in Java starts at zero).

 

    就是说我们 从上到下 从左到右 的标识这个 二叉树,并和数组中的下标对应起来,如下图所示:

   

     关系:


    • Root of tree is A[1].
    • Parent of A[i ] = A[i/2].
    • Left child of A[i ] = A[2i ].
    • Right child of A[i ] = A[2i + 1].

 

     注意:在java中数组的下标从 0 开始

3. Bulid Heap

    算法流程:

 

Begin:
Build-Heap (A[]) { // takes in an array to be heapified
A.heap-size = A.length; // heap size is number of elements in the array
for i = A.length/2 downto 1 // starting at first subtree up to root full tree
{
   Heapify(A, i); // Heapify the current subtree
}
}
End

 

    heapify-----堆化过程

 

Begin
Heapify(A[], i) // Heapify takes in our heap and index of current root node of subtree to be heapified
{
    left = LeftChild(i); // index of left child
    right = RightChild(i); // index of right child

    // if still within bounds AND left child
    if left ≤ A.heap-size AND A[left] > A[i] { 
        // greather than parent – remember largest as left child
        largest = left; 
    } else {
        largest = i; // else parent still has largest value for now
    }

    // if still within bounds AND right child
    if right ≤ A.heap-size AND A[right] > A[largest] { 
        // greather than parent – remember largest as right child
        largest = right 
    }

    if largest NOT EQUAL i { // if parent does not hold largest value
         // greather than parent – remember largest as right child
         swap A[i] and A[largest] x
         Heapify(A, largest) // Percolate down and Heapify next subtree
    }
}
End

 4. code in java

下面是java实现的构造最大堆的代码:

 

/**
 * bulid heap with array
 * 
 * @author hahakubile
 */
public class Heap {
	
	// 未作数据校验,假设 数据源ok
	public void buildHeap(int[] a) {
		int index = new Double(Math.floor(a.length/2)).intValue()-1;
		
		// 打印 未堆化前
		printArray(a);
		
		while(index>=0) {
			heapify(a, index);
			index--;
		}
		// 打印 堆化后
		printArray(a);
	}
	
	private void heapify(int[] a, int i) {
		
		int heapSize = a.length;

		int left  = leftChild(i);
		int right = rightChild(i);
		int largest = 0;
				 
		if(left<heapSize && a[left]>a[i]) {
			largest = left;
		} else {
			largest = i;
		}
		
		if(right<heapSize && a[right]>a[largest]) {
			largest = right;
		}
				
		if(largest!=i) {
			// 交换 a[i] 与 a[largest]
			int temp = a[i];
			a[i] = a[largest];
			a[largest] = temp;
			
			heapify(a, largest);
		}
	}
	
	/**
	 * 堆的特性,注意这里 root的下标从零开始
	 */
	public int leftChild(int i) {
		return 2*i + 1;
	}
	
	public int rightChild(int i) {
		return 2*i + 2;
	}
	
	// 辅助函数,打印 数组内容
	public void printArray(int[] a) {
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		for(int i : a) {
			sb.append(i).append(",");
		}
		String temp = sb.substring(0, sb.length()-1);
		
		System.out.println(temp + "]");
	}
	
	public static void main(String[] args) {
		Heap h = new Heap();
		int[] A = new int[]{4,1,3,2,16,9,10,14,8,7};
		h.buildHeap(A);
	}
}
 
### Netty 中 `java.lang.OutOfMemoryError: Java heap space` 的解决方法 Netty 是一个高性能的异步网络通信框架,广泛用于构建高并发服务端和客户端。然而,在高并发或大数据量传输场景下,Netty 应用可能遇到 `java.lang.OutOfMemoryError: Java heap space` 异常。该异常表明 JVM 的堆内存不足以满足当前运行需求,通常由堆内存不足、内存泄漏或突发流量引起。 #### 增加 JVM 堆内存 最直接的解决方式是通过调整 JVM 启动参数来增加堆内存。可以通过设置 `-Xms` 和 `-Xmx` 参数来分别指定初始堆大小和最大堆大小。例如: ```bash java -Xms2g -Xmx4g -jar your-netty-application.jar ``` 此配置将初始堆大小设置为 2GB,最大扩展到 4GB,有助于应对突发的数据流量或高并发连接请求[^5]。 #### 优化 Netty 的内存管理 Netty 提供了多种内存管理机制,包括池化内存(PooledByteBufAllocator)和非池化内存(UnpooledByteBufAllocator)。使用池化内存可以有效减少频繁的内存分配与回收,从而降低内存压力。可以通过以下方式启用池化内存: ```java EventLoopGroup group = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(group) .channel(NioServerSocketChannel.class) .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new YourHandler()); } }); ChannelFuture f = b.bind(8080).sync(); f.channel().closeFuture().sync(); } finally { group.shutdownGracefully(); } ``` 该配置将默认的内存分配器设置为池化分配器,有助于减少内存碎片和提升性能[^4]。 #### 防止内存泄漏 Netty 中的 `ByteBuf` 是内存管理的关键对象。如果未正确释放 `ByteBuf`,将导致内存泄漏。应确保每次使用完 `ByteBuf` 后调用 `release()` 方法进行释放。例如: ```java @Override public void channelRead(ChannelHandlerContext ctx, Object msg) { ByteBuf in = (ByteBuf) msg; try { // 处理数据 } finally { in.release(); } } ``` 此外,Netty 提供了内存泄漏检测工具,可以通过设置 `-Dio.netty.leakDetection.level=ADVANCED` 来启用高级泄漏检测,帮助定位未释放的 `ByteBuf` 实例[^1]。 #### 控制并发连接数与数据量 在高并发场景下,连接数过多或每个连接传输的数据量过大也可能导致堆内存溢出。可通过以下方式控制连接数和数据流: - 使用 `ChannelOption.SO_BACKLOG` 控制等待连接队列的大小。 - 使用 `ChannelOption.SO_RCVBUF` 和 `ChannelOption.SO_SNDBUF` 限制接收和发送缓冲区大小。 - 在业务逻辑中引入流量控制机制,例如限流、降级等策略。 ```java b.option(ChannelOption.SO_BACKLOG, 128) .option(ChannelOption.SO_RCVBUF, 32 * 1024) .option(ChannelOption.SO_SNDBUF, 32 * 1024); ``` 上述配置有助于缓解突发流量对堆内存的冲击[^5]。 #### 使用 Direct Buffer 减少 GC 压力 Netty 支持使用堆外内存(Direct Buffer)进行数据传输,这种方式可以减少 JVM 堆内存的使用,并降低垃圾回收(GC)频率。可以通过以下方式设置默认的分配器为直接内存分配器: ```java b.option(ChannelOption.ALLOCATOR, UnpooledByteBufAllocator.DEFAULT); ``` 需要注意的是,虽然 Direct Buffer 可以减少堆内存压力,但其分配和释放成本较高,应根据实际场景权衡使用[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值