Skip to content

Memory leaking in page.widgets() #4751

Closed

Description

@Simon-xx-yy

Description of the bug

I find memory building up in my application and traced this to the page.widgets()。
What's puzzling is that once I use the iterator it generates, even if it's only used for printing and not referencing the object in subsequent processes, a memory leak problem will occur. In the simplified script I provided, the analysis function will cause the memory to continue to grow and cannot be released, while analysis_test will not.

  • This phenomenon occurs in both 1.24.7 and 1.26.0, but when I roll back the version to 1.20.2, the memory leak disappears.

How to reproduce the bug

```python
# coding = utf-8
"""
Created on 2025/10/15 17:08
@File : pdf_mem_leak
@Author: Y
Description : 
"""
import gc
import time

import fitz
import tracemalloc

def analysis(stream_data):
    pdf_info = fitz.Document(stream=stream_data, filetype='pdf')
    tmp_list = range(len(pdf_info))
    for page_num in tmp_list:
        page = pdf_info[page_num]
        raw_info = page.get_text('rawdict')['blocks']
        page_widgets_list = page.widgets() 
        for widget_info in page_widgets_list:
            print(widget_info)
        del page_widgets_list
    pdf_info.close()
    pdf_info =None
    Tools_ = fitz.TOOLS
    Tools_.store_shrink(100)
    gc.collect()


def analysis_test(stream_data):
    pdf_info = fitz.Document(stream=stream_data, filetype='pdf')
    tmp_list = range(len(pdf_info))
    for page_num in tmp_list:
        page = pdf_info[page_num]
        raw_info = page.get_text('rawdict')['blocks']
        page_widgets_list = page.widgets()
        # for widget_info in page_widgets_list:
        #     print(widget_info)
        del page_widgets_list
    pdf_info.close()
    pdf_info =None
    Tools_ = fitz.TOOLS
    Tools_.store_shrink(100)
    gc.collect()


if __name__ =='__main__':
    file_path = r'2407.10671v4.pdf'
    tracemalloc.start(30)
    snapshot1 = tracemalloc.take_snapshot()
    last_record = []
    for i in range(100):
        print('iter is :{}'.format(i))
        bytes_data = open(file_path,'rb').read()
        analysis(bytes_data)  #with memory leak
        # analysis_test(bytes_data) #with not memory leak
        gc.collect()
        snapshot2 = tracemalloc.take_snapshot()
        top_stats = snapshot2.compare_to(snapshot1, 'traceback')
        # top_stats = snapshot2.compare_to(snapshot1, 'lineno')
        snapshot1 = tracemalloc.take_snapshot()
        top_stats = sorted(top_stats, key=lambda x: -x.size_diff)
        print("-----begin comp-----")
        for nums,stat in enumerate(top_stats[0:10]):
            if stat.size_diff<=0 or stat in last_record or stat.size_diff == stat.size or "tracemalloc" in stat.traceback.format()[0]:
                continue
            else:
                print("index is :{}\nstat info:{}".format(nums,stat))
                print("\n".join(stat.traceback.format()))
        print("-----stop comp-----\n")
        last_record = top_stats


[2407.10671v4.pdf](https://github.com/user-attachments/files/22955884/2407.10671v4.pdf)/

### PyMuPDF version

1.26.0

### Operating system

Linux

### Python version

3.9

Activity

  1. Simon-xx-yy commented on Oct 16, 2025

    @Simon-xx-yy
    Author

    You can see the memory allocated by this line in the first run as follows.

    stat info:/home//pdf_mem_leak/pdf_mem_leak2.py:56: size=3482 B (+1342 B), count=62 (+24), average=56 B
      File "/home//pdf_mem_leak/pdf_mem_leak2.py", line 56
        analysis(bytes_data)  #with memory leak
      File "/home//pdf_mem_leak/pdf_mem_leak2.py", line 21
        for widget_info in page_widgets_list:
      File "/usr/local/conda/lib/python3.10/site-packages/pymupdf/__init__.py", line 9798
        widget_xrefs = [a[0] for a in self.annot_xrefs() if a[1] == mupdf.PDF_ANNOT_WIDGET]
      File "/usr/local/conda/lib/python3.10/site-packages/pymupdf/__init__.py", line 8637
        return JM_get_annot_xref_list2(self)
      File "/usr/local/conda/lib/python3.10/site-packages/pymupdf/__init__.py", line 15621
        return JM_get_annot_xref_list( page.obj())
      File "/usr/local/conda/lib/python3.10/site-packages/pymupdf/__init__.py", line 15597
        names = extra.JM_get_annot_xref_list( page_obj)
      File "/usr/local/conda/lib/python3.10/site-packages/pymupdf/extra.py", line 117
        return _extra.JM_get_annot_xref_list(page_obj)
    

    After each loop, the memory size and amount are steadily increasing.
    After the last run, the memory allocation is as follows.

    stat info:/home//pdf_mem_leak/pdf_mem_leak2.py:56: size=143 KiB (+1969 B), count=2622 (+35), average=56 B
      File "/home//pdf_mem_leak/pdf_mem_leak2.py", line 56
        analysis(bytes_data)  #with memory leak
      File "/home//pdf_mem_leak/pdf_mem_leak2.py", line 21
        for widget_info in page_widgets_list:
      File "/usr/local/conda/lib/python3.10/site-packages/pymupdf/__init__.py", line 9798
        widget_xrefs = [a[0] for a in self.annot_xrefs() if a[1] == mupdf.PDF_ANNOT_WIDGET]
      File "/usr/local/conda/lib/python3.10/site-packages/pymupdf/__init__.py", line 8637
        return JM_get_annot_xref_list2(self)
      File "/usr/local/conda/lib/python3.10/site-packages/pymupdf/__init__.py", line 15621
        return JM_get_annot_xref_list( page.obj())
      File "/usr/local/conda/lib/python3.10/site-packages/pymupdf/__init__.py", line 15597
        names = extra.JM_get_annot_xref_list( page_obj)
      File "/usr/local/conda/lib/python3.10/site-packages/pymupdf/extra.py", line 117
        return _extra.JM_get_annot_xref_list(page_obj)
    
  2. julian-smith-artifex-com commented on Nov 21, 2025

    @julian-smith-artifex-com
    Collaborator

    Thanks for the report.

    Could you try your tests with a newer Python (at least 3.11), and the latest pymupdf (currently 1.26.6)?

    Some background:

    • Since pymupdf-1.23.9, pymupdf changed to use a new "rebased" implementation.
    • The new implementation seems to expose some leak problems in Python versions before 3.11.
    • We have various leak tests that we only run on Python>=3.11, and which have been passing for a long time now.
  3. Roman-Bober commented on Jan 14, 2026

    @Roman-Bober

    HI @julian-smith-artifex-com the issue is also reproducible for me
    for python 3.11.12 , and pymuPDF both 1.26.3 and 1.26.6(on this one leakage is even worse with this leak pymupdf/extra.py:189)
    attaching tracemalloc log , the leakage

    tracemalloc.log

    is within

  4. robinwatts commented on Jan 19, 2026

    @robinwatts
    Collaborator

    Can you reattach the file in question, please? 2407.10671v4.pdf.

    The link about seems to be broken.

  5. added 4 commits that reference this issue on Jan 21, 2026
    1c1b837
    098e3b9
    d2af956
    b49a9a0
  6. julian-smith-artifex-com commented on Feb 11, 2026

    @julian-smith-artifex-com
    Collaborator

    Fixed in PyMuPDF-1.27.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions