Android使用dma_buf分析Low Memory问题

文章介绍了如何通过adbshell命令检查Android设备的LostRAM,以及如何追踪LostRAM与ION的关系,通过查看DMABUFFER使用情况和进程使用状况来定位问题。此外,文中还提到了内存不足可能与Activity切换时保存的快照和未及时释放的GraphicsBuffer有关。
摘要由CSDN通过智能技术生成

一,检查是否有过多的Lost RAM
可通过如下命令查看结果

adb shell 
#dumpsys meminfo | grep RAM

结果如下:

Applications Memory Usage (in Kilobytes):
Uptime: 347257 Realtime: 347257

Total PSS by process:
    189,021K: BeanVRService (pid 1927)
    114,683K: com.gwm.app.gwmvrwakeup (pid 2577)
    111,974K: system (pid 853)
    105,917K: com.gwm.app.hvac (pid 3207)
     90,517K: com.android.systemui (pid 1367)
     85,671K: com.beantechs.beanmap (pid 14329)
     69,019K: com.beantechs.tts.server (pid 2323)
     65,958K: com.beantechs.map.watchdog (pid 3336)
     62,885K: com.gwm.app.launcher (pid 1692 / activities)
     43,224K: com.beantechs.weatherservice (pid 2750)

省略很多

Total RAM: 6,120,992K (status normal)
 Free RAM: 2,122,499K (  203,671K cached pss +   888,700K cached kernel + 1,030,128K free)
 Used RAM: 3,044,927K (2,202,219K used pss +   842,708K kernel)
 Lost RAM:   953,554K
     ZRAM:        12K physical used for         0K in swap (1,048,572K total swap)
   Tuning: 512 (large 512), oom   322,560K, restore limit   107,520K (high-end-gfx)

也可以敲 cat /proc/meminfo 查看 

二,找到Lost RAM 来源
ION是内核提供的内存管理框架。 Lost RAM与ION相关。
1,查看ION设备节点

adb shell "lsof | grep /dev/ion"


结果:

audio@2.0-servi 458 root 24r CHR 10,62 0t0 14545 /dev/ion
surfaceflinger 626 system 20r CHR 10,62 0t0 14545 /dev/ion
surfaceflinger 626 system 22r CHR 10,62 0t0 14545 /dev/ion
system_server 782 system 115r CHR 10,62 0t0 14545 /dev/ion
system_server 782 system 173r CHR 10,62 0t0 14545 /dev/ion

2,查看DMA BUFFER整体使用情况

adb shell "cat /sys/kernel/debug/dma_buf/bufinfo"


结果:

Dma-buf Objects:
size flags mode count exp_name buf name
00786432 00000002 00000007 00000001 msm_hab_linux dmabuf2338
Attached Devices:
Total 0 devices attached
00786432 00000002 00000007 00000001 msm_hab_linux dmabuf2337
Attached Devices:
Total 0 devices attached
00028672 00000002 00000007 00000005 ion-system-545-vendor.qti.hard dmabuf2336
Attached Devices:
Total 0 devices attached
...
Total 1619 objects, 765116416 bytes

3,查看dma buf在各个进程的使用情况:

adb shell "cat /sys/kernel/debug/dma_buf/dmaprocs | grep PID"

注意,上述文件节点,需要配置CONFIG_DEBUG_FS

代码参考:kernel/msm-5.4/drivers/dma-buf/dma-buf.c
如下:

surfaceflinger (PID 629) size: 101464
wmscenelauncher (PID 1928) size: 86856
om.gwm.app.hvac (PID 3431) size: 86848
com.android.car (PID 1142) size: 65136
composer@2.2-se (PID 443) size: 47748
ais_v4l2_proxy (PID 357) size: 46272
system_server (PID 857) size: 21720
ndroid.settings (PID 4639) size: 16364
ndroid.systemui (PID 1157) size: 14980
id.multidisplay (PID 1599) size: 6484
msmartassistant (PID 2342) size: 668
qseecomd (PID 320) size: 544
audio@2.0-servi (PID 429) size: 512
gwm.app.account (PID 2735) size: 8
beantee@1.0-ser (PID 474) size: 8

4,复现问题,查看哪些操作,可以导致模块的size不停增加。如果一直增加说明有异常。

5,adb shell里面查看/sys/kernel/debug/dma_buf/下的dmaprocs和bufinfo,查看异常的dma_buf指向那些模块,并分析问题来源。

6,以上可以发现安卓原生的问题Activity切换的时候,Android会保存快照,申请的GraphicsBuffer如果没有及时释放,会引起内存不足。屏蔽Android快照功能即可。

以下是使用DMA和循环队列接收UART数据的示例代码: ```c #include "stm32f4xx_hal.h" #define UART_RX_BUF_SIZE 256 UART_HandleTypeDef huart; DMA_HandleTypeDef hdma_usart_rx; uint8_t uart_rx_buf[UART_RX_BUF_SIZE]; volatile uint16_t uart_rx_head = 0; volatile uint16_t uart_rx_tail = 0; void HAL_UART_MspInit(UART_HandleTypeDef *huart) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if (huart->Instance == USART1) { /* Peripheral clock enable */ __HAL_RCC_USART1_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /**USART1 GPIO Configuration PB6 ------> USART1_TX PB7 ------> USART1_RX */ GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART1; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* USART1 DMA Init */ /* USART1_RX Init */ hdma_usart_rx.Instance = DMA2_Stream2; hdma_usart_rx.Init.Channel = DMA_CHANNEL_4; hdma_usart_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_usart_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_usart_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_usart_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_usart_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_usart_rx.Init.Mode = DMA_CIRCULAR; hdma_usart_rx.Init.Priority = DMA_PRIORITY_LOW; hdma_usart_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; if (HAL_DMA_Init(&hdma_usart_rx) != HAL_OK) { Error_Handler(); } __HAL_LINKDMA(huart, hdmarx, hdma_usart_rx); /* USART1 interrupt Init */ HAL_NVIC_SetPriority(USART1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(USART1_IRQn); } } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart->Instance == USART1) { // Move tail pointer to next position uart_rx_tail = (uart_rx_tail + 1) % UART_RX_BUF_SIZE; } } void USART1_IRQHandler(void) { HAL_UART_IRQHandler(&huart); } void uart_init(void) { huart.Instance = USART1; huart.Init.BaudRate = 115200; huart.Init.WordLength = UART_WORDLENGTH_8B; huart.Init.StopBits = UART_STOPBITS_1; huart.Init.Parity = UART_PARITY_NONE; huart.Init.Mode = UART_MODE_TX_RX; huart.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart) != HAL_OK) { Error_Handler(); } } void dma_init(void) { __HAL_RCC_DMA2_CLK_ENABLE(); HAL_NVIC_SetPriority(DMA2_Stream2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn); } void DMA2_Stream2_IRQHandler(void) { HAL_DMA_IRQHandler(&hdma_usart_rx); } void start_uart_dma_rx(void) { HAL_UART_Receive_DMA(&huart, uart_rx_buf, UART_RX_BUF_SIZE); } uint8_t uart_rx_buf_pop(void) { uint8_t data = uart_rx_buf[uart_rx_head]; uart_rx_head = (uart_rx_head + 1) % UART_RX_BUF_SIZE; return data; } uint16_t uart_rx_buf_size(void) { if (uart_rx_head <= uart_rx_tail) { return uart_rx_tail - uart_rx_head; } else { return UART_RX_BUF_SIZE - (uart_rx_head - uart_rx_tail); } } int main(void) { HAL_Init(); uart_init(); dma_init(); start_uart_dma_rx(); while (1) { if (uart_rx_buf_size() > 0) { uint8_t data = uart_rx_buf_pop(); // Process received data } } } ``` 在上述代码中,我们使用 HAL 库来初始化 UART 和 DMA。我们使用循环队列来存储接收到的 UART 数据,这样可以避免数据丢失和覆盖。我们还实现了一个简单的 API 来访问循环队列中的数据。 在 `main()` 函数中,我们不断检查循环队列中是否有接收到的数据,并进行处理。当收到新数据时,我们将它从循环队列中弹出并进行处理。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值