diegomura / react-pdf

📄 Create PDF files using React
https://react-pdf.org
MIT License
14.28k stars 1.12k forks source link

"Cannot enlarge memory arrays" error when document is big. #314

Closed binchik closed 5 years ago

binchik commented 5 years ago

OS: MacOS 10.13.6

React-pdf version: 1.0.0-alpha.17

Description: Hello! I'm using react-pdf to generate payment reports for a website I'm working on. The reports can often get really big, 400+ pages long. But I can only generate about 450 pages on my machine. If I try to render more, it hangs and finally crashes with the following error:

Cannot enlarge memory arrays. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value 134217728, (2) compile with -s ALLOW_MEMORY_GROWTH=1 which allows increasing the size at runtime but prevents some optimizations, (3) set Module.TOTAL_MEMORY to a higher value before the program runs, or (4) if you want malloc to return NULL (0) instead of this abort, compile with -s ABORTING_MALLOC=0

I'm rendering the pdf reports in browser with PDFViewer.

How to replicate issue including code snippet (if applies):

I made a reproducible demo here (almost same code as in pageWrap example but rendering the same Don Quijote page content 1600 times): https://github.com/binchik/react-pdf-crash-example

It loads for about 5-10 minutes then crashes with the "Cannot enlarge memory arrays" error.

Neil-G commented 5 years ago

@diegomura hey, just wanted to let you know that I've reproduced this as well, would appreciate an update if you're able to help- thanks!

diegomura commented 5 years ago

Thanks for reporting it. Never experienced this with the new version because I didn't test documents that big.What page size are you using? Did you discover from what page threshold this happens? Providing that data would be helpful

Neil-G commented 5 years ago

@diegomura , I'm using the default page size. Or do you mean wrapping chunks of content in a <Page> component? I think the largest pdf I was able to print without crashing was ~40 pages. Here's a screenshot of the error message in the browser:

screen shot 2018-09-25 at 6 18 39 pm

Thanks and let me know how I can help you address this

diegomura commented 5 years ago

Hey @Neil-G . Sorry for the absence. I was on vacations for awhile. Can you test the last version to check if this still happens? If it does, I would appreciate if you can provide me a way to reproduce this Thanks 😄

jason955 commented 5 years ago

Hi @diegomura , can confirm this error still persists. My stack trace looks exactly like @Neil-G 's post. I'm currently trying to dynamically render a huge amount of content and place it inside a single tag. I can get up to about 40 pages before I get this error. Do you think this is caused by my use of a single Page tag? It would make sense to me if the Page components children array can only be so big. Will do some testing and report back.

AirborneEagle commented 5 years ago

I am also now running into this issue. The strange thing is, that my document is only 2 pages long. . . .

I am building a Sales Order. And to me it seems that I am not submitting an overly large amount of data.

Do we yet know what the cause of this issue is? what information can I provide to help solve this problem? version: 1.0.0-alpha.25

AirborneEagle commented 5 years ago

Ok. I just discovered that My Issue is a little different. I have a View that has wrap=false. The problem is that the view contains dynamic content. when the content grows to a point that is bigger than can fit on a page, then I am guessing react-pdf keeps wrapping the whole view to the next page, hoping that the view will fit on the next page, until finally it has generated XXX number of pages and then runs out of memory.

When wrap=true, the the view contents are split, which might be ok, except when it wraps, the first part of the View contents get compressed together. as seen in this picture. image

I should probably create a separate issue for this.

AirborneEagle commented 5 years ago

Here is the issue I created. https://github.com/diegomura/react-pdf/issues/416

limaleandro1999 commented 5 years ago

Did you find any solution?

jason955 commented 5 years ago

I'm not sure if this is going to make it back to the git thread as I'm responding via email. Initially I was storing all this data in one giant jsonobject that had arrays holding all of my data as values and specific keys as keys. I swapped it to a regular array and refactored code and didn't get the error anymore.

On Fri, Apr 12, 2019, 8:38 AM Leandro Lima notifications@github.com wrote:

Did you find any solution?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/diegomura/react-pdf/issues/314#issuecomment-482558777, or mute the thread https://github.com/notifications/unsubscribe-auth/AINV_WJVPafUprDtfPby-yZuZVeQ7d9yks5vgH4_gaJpZM4W1nat .

tommmyy commented 5 years ago

@diegomura I think the issue is still not gone in v1.5.6.

Try to increase 1000 to 10000 in following:

https://react-pdf.org/repl?code=3187b0760ce02e00408a057025803c450298c0bc300500943807c300de3005030c01386502b58fb53003c00888c0202d86305189b1aec002804300e659a004f003619b1905ca2003a004620009bc80be226a9f201056ad49f2f0046000c4e0a6806649162c29afa4800e7878280034304844d8a478a2a60090ec002a1828b0ea2a6a504a185a9829863000d618f2aa48c6316600a22c082c8a08d292b4307a588a923000b29260c0001692a1ad30bcf2203060207cdaf413e3008ec818b4e392a0b47a4d02a193300315a67c08fde35048187c7e0b0858006e48b700b71db57b489b8ad2e3c38a20102d6d1e800bc3a8218249a01e650ad42924dad11a071a0f4ced20420ce83c478b15ced500c1e43046a7dc6eb7a1e840b44d0c000aa600e8813c1d61a4849303e0010ffeb73587516182448c9a60658814210565f890c00033dd421ecae5cdfad9218dd7eff427f26628bf8c0353008073b470bfb0505ca2106000560a837dd9622882c33e002f961f95953242ec590047b87bc981d03452f83eafb3b05a0483f19ef2ff941e8ff4f6d130ff61840107b35b9cc09b6a65514746c941be182648dc0c07abc70d361020b86b70ad3530a1602b24119bb857ea14982a6430af72961531c34205328842e2f53f46d98cce1881f0c5faf9f3c7b3041126e4171e87420583eb81ac26aacb0b33016e7929480046f1510417b926d4a49819e3babf673b129816a0e9245f0607e507085240bc177f978269770c5092030d100661f524415c0dd93c0c11a0bc433d45b1f5db02500960d7205cb2152e719093f1da10542702214790541020284a0d058b159806c4ab35c6032d7c0bdda41df438596491a9000c56824025513414d8f447cc01b9a0159053e9de564be4bc375827d5e010f04fd334776b11f5012e65050240e512d802403163df16193b66155362c06b41032d1f15934900006e225ac722e15a01a5359a42440a41f49f83a4ec416a510739e81615a6739a7e5054c0bf6e250999042994ac7c32db536181c6441b23843a3c1c0b054b7180678b3e2029b2415c65904673413a8f5491fcca5b23026e005a02c1ff719b2601e4ed104021615a9c0ab96868dc06b41860db951420479c30d10d2c15a5b47f42b5a3caa6e3df576940aab0f30afc514776811725c6824068b4c3a2b9f10e9d4d2c561186e211429804d680f929ac1313e92b173472f40012f8b5d9ee8953e0c3be9a15e3f16a00b929bd961520e788007a24852130970200843062760a9a91647a759ee178010841100810b0c10b284a064f00a04d1e869014cc1683c0c83615c04b14790002e1800072001e420001dd593d035f346808168601d58d6fa280a03f020556a9aa75c716b469161b39804d06caa6202a6fe7d7143d0a9db8ec00198a980134007d0480069000d40036100000e001d4405b9b41a4f410ef848e000d0013924731cc4d1add7035ca10c0164598da04353253b70001949b8c05bbe8300613dfa1244c1e5b6174031d5856cc4f4f43d023048403f1d590e00566374c09ea7b01a400085d0613d584e979895788c00097bd28a115979ff79a10c65ece2819451e622768416e9020430756002600059979a172280e611422530016d802ee65846c9fb8b192cacd5a6b1d6fed0d9b01be6c14694053cb411f99867e5015fbbf7567613f9ff212c9100700e90a0335b80ab4b40a072e268d2cc016f6b6531d5b7f070cbd5049b040da0ef83f720d025f9bf0fe300ec327121be0110fa421c4284540581275e076b3d606cabb5f5be643b061c461322c45c89c1e2df0688bb0bfc62000a012022d9f9484ae1e43d0d30b83144786510917eb64000b400094a60f4751301b85845f0b21b44d02914c2e3b2c77617cc455f1d1d22c009f79267ca00c4c709c25072f2ee924b0608c31c22087e8c91ba39876f3613013f864b30162285508d6343658389a0a017e2e48d6d21e83d8ae1cbd3d2c800072fc196ae4b1e2bcfe120338e002d9410808c9fc86026930170718d91243742b0be0f3caa698650ae0a03ab2d9341e4b482b6fb2484d4ab1d42205d09212d32905b0e9c501c6a09aec2d281788c06b0a03884e032525a081ba781d806534098060153620b5c800

cleggypdc commented 4 years ago

I've managed to produce this recently in 1.6.8 although we're using it with PDFs that are 80+ pages long, and sometimes contain images. If I figure it out I'll come back to this thread.

jtart commented 4 years ago

@diegomura This issue, or one similar to it still exists and is replicable in a unit test. react-pdf struggles to render large pieces of text. See the unit test and result

Unit test

image

Result

image
venkatgoud commented 3 years ago

I am trying to generate a pdf of about 100 pages(all text) and facing the same issue. Using 2.0.0-beta.6.

mcronline commented 3 years ago

Same problem here. Rendering a large amount of views and texts to display data tables. After about 25 pages, it crashes.

clarson1229 commented 3 years ago

I too am also getting the same error. image It does not happen every time though. I am using the 'PDFDownloadLink' component so that when a user clicks on a button the modal is displayed and the PDF component is inside the modal so it then begins to generate the PDF. I am working with an array of objects and it appears anything over 2000 data points in the array causes the error to happen. (about 65 pages in length)

I am also seeing that the error will happen when I try and create PDFs with smaller data sets as well if the user generates a pdf more than 1 time.

const CSVTableRows = (props) => {
    const { items } = props;
    const rows = items.map( (x, index) => 
        <View style={styles.rows} key={`Row-${index}`}>
            <Text style={styles.row1}>{x.date}</Text>
            <Text style={styles.row2}>{x.measure}</Text>
        </View>
    )
    return (<Fragment>{rows}</Fragment> )
};

This is the component generating the dynamic rows.

pandeysabin commented 3 years ago

Same problem here. Rendering a large amount of views and texts to display data tables. After about 25 pages, it crashes.

experiencing the same behavior for large documents.

pnxbill commented 3 years ago

@diegomura , I'm using the default page size. Or do you mean wrapping chunks of content in a <Page> component? I think the largest pdf I was able to print without crashing was ~40 pages. Here's a screenshot of the error message in the browser:

screen shot 2018-09-25 at 6 18 39 pm

Thanks and let me know how I can help you address this

This was helpful. I realized that one page component will fail to render if the dynamic content being rendered inside is too big. Some people said ~45 pages. So I tried wrapping the dynamic content inside <Page> tags separately and it worked!!

Basically, if you're rendering dynamically, you'll probably have an array of data that you map to create your Views. In my case I divided the initial array of 400 objects into 10 arrays of 40 and wrapped a Page component around each array.

Theses numbers are not fixed, it depends on how many elements are on your initial array and how much memory they need. The point is: there seems to be a memory limit on the Page component and the workaround is to generate more Page components instead of relying entirely on page wrap functionality.

adisrael commented 3 years ago

@diegomura , I'm using the default page size. Or do you mean wrapping chunks of content in a <Page> component? I think the largest pdf I was able to print without crashing was ~40 pages. Here's a screenshot of the error message in the browser:

screen shot 2018-09-25 at 6 18 39 pm

Thanks and let me know how I can help you address this

This was helpful. I realized that one page component will fail to render if the dynamic content being rendered inside is too big. Some people said ~45 pages. So I tried wrapping the dynamic content inside <Page> tags separately and it worked!!

Basically, if you're rendering dynamically, you'll probably have an array of data that you map to create your Views. In my case I divided the initial array of 400 objects into 10 arrays of 40 and wrapped a Page component around each array.

Theses numbers are not fixed, it depends on how many elements are on your initial array and how much memory they need. The point is: there seems to be a memory limit on the Page component and the workaround is to generate more Page components instead of relying entirely on page wrap functionality.

I just had the same issue, my document doesn't have that much pages but it has a lot of images. Separating in different <Page> components worked! Thank you @pnxbill

salihonder commented 3 years ago

Wrapping with a Page component solves the problem mostly but If the image is too big it will not work again... In that case, my solution was splitting images base on the array size then it works fine.

krishankantray commented 3 years ago

@salihonder can you please explain your solution , I am facing the same problem . When I remove the image (A4 size full screen) then it works fine.

monzerhijazi commented 3 years ago

Should we reopen this issue? I Run into the same issue with a really simple PDF that just has a Text component with 10K characters.

pnxbill commented 3 years ago

Should we reopen this issue? I Run into the same issue with a really simple PDF that just has a Text component with 10K characters.

Try dividing the text between pages. Do not use only one page for a gigantic content.

sdzhangtao commented 3 years ago

Should we reopen this issue? I Run into the same issue with a really simple PDF that just has a Text component with 10K characters.

Try dividing the text between pages. Do not use only one page for a gigantic content.

We have an application that creates the pdf based on user's input. We don't know how long the user input might be. It simply stops working when the input text is beyong 10k. Dividing the text between pages is actually very hard to do in reality especially when we don't know how long the text might be. This workaround is not ideal. When the input text size is beyong 10k, even I boosted up yoga-layout from 128M to 0.5G memory, it still crashes. I profiled the application with both CPU and memory, The page-wraping.es.js line 213 wrap function spent most the CPU time 3166ms out of 4860ms. And mergeWithKey, mergeDeepWithKey spent most of the memory. I created a simple project to demonstrate this located at github. https://github.com/sdzhangtao/crashing-react-pdf Also I attached the cpu and memory profiling picture.

sdzhangtao commented 3 years ago

Here is the picture for the cpu and memory profiling results. crashing-pdf-cpu-profiling crashing-pdf-memory-profiling

salihonder commented 3 years ago

@salihonder can you please explain your solution , I am facing the same problem . When I remove the image (A4 size full screen) then it works fine.

it is here my solution Simply if u wrap each of your components with a pages wrapper component then memory issue will be gone. There is another way to increase the memory directly ..search for "Cannot enlarge memory" and find the package on node module and increase the number... but the code below should be simple enough.

const PageWrapper = (props: any) => (
  <Page style={styles.body}>
    {props.children}
  </Page>
);

Sometime this error happens when a large image is forced to fit the page. In that case, if you taking the image with html2canvas try to optimize size and quality or try to make the component split with a classname and take each class images.

const getTableImages = async (pcUnits: any) => {
  const imageTables3 =
    document.getElementsByClassName('graph') ||
    document.createElement('div');

  let table3Data: any = [];
.
.
.

  const renderTable3Canvas = async (imageTable: any) => {
    const tableCanvas = await html2canvas(imageTable as HTMLElement, {
      logging: false,
      scrollY: -window.scrollY
    });
    table3Data.push(tableCanvas.toDataURL('image/jpeg', 0.85));
  };

  // @ts-ignore
  const promisesTable3 = Array.from(imageTables3).map(renderTable3Canvas);
  await Promise.all(promisesTable3);

  return {
    pctables3: table3Data,
    unitHeaderIndices
  };
};

or the best way to render faster without any memory issues is designing the react component directly inside of pdf

I designed the tables like this..it is indeed more complicated since my project but I simplified here..

u can copy paste and test it here

https://react-pdf.org/repl


const PodTableContainer = (props) => {
  const {
    headers,
    title,
    data,
    labels,
    headerSizes,
    fontSize,

  } = props;

  return (
    <View style={[{ paddingTop: 0, width: '100%', backgroundColor: 'white' }]}>
      <View style={[PrintStyles.table, { fontSize }]}>
        <View style={[PrintStyles.th, PrintStyles.tr]}>
          {headers.map((header, i) => (
            <View
              key={`header-${header}-${title}-${i}`}
              style={[
                PrintStyles.td,
                PrintStyles.header,
                {
                  flex: headerSizes[i],
                  backgroundColor: '#f0f1f4'
                }
              ]}
            >
              <Text style={{ fontSize: fontSize * 0.7, fontWeight: 'bold' }}>
                {header}
              </Text>
            </View>
          ))}
        </View>
        <View>
          {data.map((row, i) => (
            <View
              style={[
                PrintStyles.tr
                // Styles.getCellShade({ shadedline: i % 2 !== 0 })
              ]}
              key={`${title}-${i}`}
            >
              {labels.map((label, j) => (
                <View
                  break
                  style={[
                    PrintStyles.td,
                    { flex: headerSizes[j] }]}

                  key={`${label}-${j}`}
                >
                  <View>
                    <Text
                      style={{
                        fontSize: fontSize * 0.6,
                        textTransform: 'capitalize',
                        color: '#373737',
                        fontWeight: 500,
                        fontFamily: 'Oswald',
                        margin: 'auto',
                        width: '100%'
                      }}
                    >
                      {row[label]}
                    </Text>
                  </View>
                </View>
              ))}
            </View>
          ))}
          {data.length === 0 && <Text>{props.noDataMessage}</Text>}
        </View>
      </View>
    </View>
  );
};

const CardWrapper = (props) => {
  return (
    <View style={PrintStyles.card}>
      <View>
        <View
          break={props.headerBreak || false}
          style={[
            PrintStyles.cardContent,
            { height:  21 }
          ]}
        >

          <View style={PrintStyles.titleWrapper} break>

            <Text style={PrintStyles.title}>{props.title}</Text>
          </View>
          <View style={PrintStyles.dateWrapper} break>

              <Text style={PrintStyles.timestamp}>{`Last updated ${props.lastUpdated}`}</Text>

          </View>
        </View>
        {props.children}
      </View>
    </View>
  );
};

const PodTablePrint = (props) => {
  return (
    <CardWrapper {...props}>{<PodTableContainer {...props} />}</CardWrapper>
  );
};

const Quixote = () => (
  <Document>
    <Page style={PrintStyles.body}>
      <Text style={PrintStyles.pageTitle} >
       Table Example
      </Text>
     <PodTablePrint
        title="MyTable"
        headers={['id','label2','label3','label4','label5','date']}
        data={[
          {col1: 1,col2:'My column', col3: 'here we go', col4: 22, col5: 'super', col6: '2020-11-12'},
          {col1: 2,col2:'My column', col3: 'here we go', col4: 22, col5: 'super', col6: '2020-11-13'}
        ]}
        labels={['col1','col2','col3','col4','col5','col6']}
        headerSizes={[1, 1, 1, 1, 1, 1]}
        fontSize={7}
        lastUpdated="11:11 PM"
        noDataMessage="no data"
      />
    </Page>
  </Document>
);

Font.register({
  family: 'Oswald',
  src: 'https://fonts.gstatic.com/s/oswald/v13/Y_TKV6o8WovbUd3m_X9aAA.ttf'
});

const PrintStyles = StyleSheet.create({
   body: {
    paddingTop: 25,
    paddingBottom: 20,
    paddingHorizontal: 25
  },
  pageTitle: {
    fontSize: 24,
    textAlign: 'center',
    fontFamily: 'Oswald'
  },
  // Wrapper styles
    card: {
    borderRadius: 8,

    backgroundColor: 'white',
    marginBottom: 24
  },
  title: {
    fontSize: 7,
    fontWeight: 600,
    color: '#373737',
    marginLeft: 1
  },
  subtitle: {
    fontSize: 18,
    marginVertical: 5,
    fontFamily: 'Oswald'
  },
  timestamp: {
    fontSize: 7,
    fontStyle: 'italic',
    color: '#757575',
    paddingRight: 6
  },
  cardContent: {
    display: 'flex',
    justifyContent: 'space-between',
    alignItems: 'center',
    //height: 21,
    marginBottom: 4,
    flexDirection: 'row'
  },
  titleWrapper: {
    flexDirection: 'row',
    justifyContent: 'flex-start',
    display: 'flex',
    alignItems: 'center',
    marginLeft: 1
  },
  dateWrapper: {
    justifyContent: 'flex-end',
    display: 'flex',
    alignItems: 'center'
  },
  container: {
    backgroundColor: 'white'
  },
  image: {
    height: 6,
    width: 6
  },
 // Table styles
  table: {
    display: 'flex',
    flexDirection: 'column',
    flexWrap: 'nowrap',
    margin: 0,
    flex: 1
  },

  th: {
    display: 'none',
    fontWeight: 700,
    minHeight: 20
  },

  header: {
    justifyContent: 'flex-start',
    borderRadius: 2,
    marginLeft: 1.4,

    alignItems: 'center',
    backgroundColor: '#f0f1f4'
  },

  tr: {
    width: '100%',
    display: 'flex',
    flexDirection: 'row',
    flexWrap: 'nowrap',
    flex: 1,
    minHeight: 18
  },

  td: {
    display: 'flex',
    flexDirection: 'row',
    justifyContent: 'flex-start',
    alignItems: 'center',
    paddingHorizontal: 4,
    paddingVertical: 2,
    marginLeft: 1.4,
    marginTop: 0.5,
    marginBottom: 0.5
  },

});

ReactPDF.render(<Quixote />);
hkh95 commented 3 years ago

I have a double map function, and i think i've solved this by using the render prop on View tag to display the larger data set.

arr1.map((place, index) => (
  <View key={index}>
      <View>
        <Text>{place}</Text>
      </View>
      <View style={styles.worksContainer}>
        {arr2.map((x, index) => (
            <View
              key={index}
              render={() => (
                <View key={index}>
                  <View>
                    <Text>{x}</Text>
                  </View>
                </View>
              )}
            />
          ))}
      </View>
    </View>
));

At least it works this way for me but i got an error on this code below

arr1.map((place, index) => (
  <View key={index}>
      <View>
        <Text>{place}</Text>
      </View>
      <View style={styles.worksContainer}>
        {arr2.map((x, index) => (
            <View key={index}>
              <Text>{x}</Text>
            </View>
          ))}
      </View>
    </View>
));

I'm not quite sure why this works but may be a solution for others...

BatchCodes commented 3 years ago

I had this issue and found it was because I had wrap={false} around components which were getting bigger than 1 page. I removed the wrap={false} and the problem stopped