Skip to content

Shrink TextAttributes by 56 bytes - #58802

Open
ide wants to merge 1 commit into
react:mainfrom
expo:text-attributes-size
Open

ide wants to merge 1 commit into
react:mainfrom
expo:text-attributes-size

Conversation

@ide

@ide ide commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

Summary:

TextAttributes is copied into every AttributedString fragment and is part of every text measure cache key so its memory usage adds up. We can reduce the size of its fields by several bytes, saving about 22% on Android and 15% on iOS. Another way to think of this is that it frees up a memory budget to add support for features like inheritable styles.

The enum types in TextAttributes use uint8_t (1 byte) where possible. There are some exceptions like FontWeight which uses uint16_t because it has values up to 900, and FontVariant stays int.

Also, there is an optimization around the ordering of font-related fields to reduce byte-alignment gaps by ordering all the 4-byte fields first, followed by 2-byte optionals. This is small and saves 16 bytes on iOS and 8 bytes on Android, but is also a win just from reordering a few fields that are close to each other. There is a test case to keep this optimization in place.

Platform Before After
Android 256 bytes 200 bytes
iOS 376 bytes 320 bytes

I also checked that -O3 didn't do these optimizations already.

Changelog:

[INTERNAL] [CHANGED] - Shrink each TextAttributes instance by 56 bytes

Test Plan:

Fantom tests and the attributedstring gtests.

Why
===
`TextAttributes` is copied into every `AttributedString` fragment and is part of every text measure cache key so its memory usage adds up. We can reduce the size of its fields by several bytes, saving about 22% on Android and 15% on iOS. Another way to think of this is that it frees up a memory budget to add support for features like inheritable styles.

How
===
The enum types in `TextAttributes` use `uint8_t` (1 byte) where possible. There are some exceptions like `FontWeight` which uses `uint16_t` because it has values up to 900, and `FontVariant` stays `int`.

Also, there is an optimization around the ordering of font-related fields to reduce byte-alignment gaps by ordering all the 4-byte fields first, followed by 2-byte optionals. This is small and saves 16 bytes on iOS and 8 bytes on Android, but is also a win just from reordering a few fields that are close to each other. There is a test case to keep this optimization in place.

| Platform      | Before    | After     |
| ------------- | --------- | --------- |
| Android       | 256 bytes | 200 bytes |
| iOS           | 376 bytes | 320 bytes |

I also checked that `-O3` didn't do these optimizations already.

Test Plan
===
Fantom tests and the `attributedstring` gtests.
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 1, 2026
@facebook-github-tools facebook-github-tools Bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Oct 1, 2026
@meta-codesync

meta-codesync Bot commented Oct 1, 2026

Copy link
Copy Markdown

@Abbondanzo has imported this pull request. If you are a Meta employee, you can view this in D122902861.

@cortinico

Copy link
Copy Markdown
Contributor

Can you please update the .api file?

This branch has not been deployed

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

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants