[FFmpeg-trac] #5224(avcodec:new): Excessive memory use in H.264 decoder with threading enabled

FFmpeg trac at avcodec.org
Tue Feb 9 13:49:17 CET 2016


#5224: Excessive memory use in H.264 decoder with threading enabled
---------------------------------+---------------------------------------
             Reporter:  jkqxz    |                     Type:  defect
               Status:  new      |                 Priority:  normal
            Component:  avcodec  |                  Version:  unspecified
             Keywords:           |               Blocked By:
             Blocking:           |  Reproduced by developer:  0
Analyzed by developer:  0        |
---------------------------------+---------------------------------------
 Given a stream with gaps in frame_num, the threaded decoder may allocate
 many more frames than it should.  (Up to thread count * num_ref_frames
 whole frame buffers.)

 See attached stream.

 This has parameters:
 * Baseline profile
 * num_ref_frames = 16
 * log2_max_frame_num_minus4 = 12
 * gaps_in_frame_num_value_allowed_flag = 1

 The stream is then a single IDR frame of black, followed by all-skip P
 frames with frame_num decreasing by one each time (65535, 65534, ...).

 Decode this stream with:
 {{{
 % ffmpeg -v 55 -vsync 0 -threads 8 -thread_type frame+slice -i
 large_frame_num_gaps.264 -f null -
 }}}
 Virtual memory use is much higher than expected, though this is rather
 hard to see.  (Since the frames are never actually touched, the real
 memory use is not excessive.)

 To see the problem more effectively, apply the following patch to
 instrument malloc/free:
 {{{
 diff --git a/libavutil/mem.c b/libavutil/mem.c
 index 8dfaad8..bddb0d1 100644
 --- a/libavutil/mem.c
 +++ b/libavutil/mem.c
 @@ -69,6 +69,7 @@ void  free(void *ptr);
   * Note that this will cost performance. */

  static size_t max_alloc_size= INT_MAX;
 +static void *big_mem_list[100];

  void av_max_alloc(size_t max){
      max_alloc_size = max;
 @@ -139,6 +140,18 @@ void *av_malloc(size_t size)
      if (ptr)
          memset(ptr, FF_MEMORY_POISON, size);
  #endif
 +
 +#if 1
 +    if(size > 1000000) {
 +        int i;
 +        av_log(0, AV_LOG_DEBUG, "malloc(%zu) = %p\n", size, ptr);
 +        for(i = 0; i < FF_ARRAY_ELEMS(big_mem_list) && big_mem_list[i];
 i++);
 +        if(i >= FF_ARRAY_ELEMS(big_mem_list))
 +            av_assert0(0 && "Too many big allocations.");
 +        big_mem_list[i] = ptr;
 +    }
 +#endif
 +
      return ptr;
  }

 @@ -227,6 +240,19 @@ int av_reallocp_array(void *ptr, size_t nmemb, size_t
 size)

  void av_free(void *ptr)
  {
 +#if 1
 +    if(ptr) {
 +        int i;
 +        for(i = 0; i < FF_ARRAY_ELEMS(big_mem_list); i++) {
 +            if(big_mem_list[i] == ptr) {
 +                av_log(0, AV_LOG_DEBUG, "free(%p)\n", ptr);
 +                big_mem_list[i] = 0;
 +                break;
 +            }
 +        }
 +    }
 +#endif
 +
  #if CONFIG_MEMALIGN_HACK
      if (ptr) {
          int v= ((char *)ptr)[-1];
 }}}

 Now the first command will abort with threads = 8 (and not with threads =
 1), because it tries to allocate more than 100 frame buffers.

--
Ticket URL: <https://trac.ffmpeg.org/ticket/5224>
FFmpeg <https://ffmpeg.org>
FFmpeg issue tracker


More information about the FFmpeg-trac mailing list